Is there a way to unnest (or unchain) the chained anonymous functions below? I include my try after the script with nested anonymous functions. I want to define separately each function defined anonymously on its own to see clearly and understand where each function starts and ends and what they do. Thanks.
A script with nested anonymous functions that I want to separate (taken from here):
<html>
<script>
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, function(response) {
var firstParagraph = response.dom;
//}); moved to end to get the variable firstParagraph
var formData = new FormData();
formData.append("url", tab.url);
formData.append("title", tab.title);
formData.append("pitch", firstParagraph);
//formData.append("user_tag_list", "tag1, tag2");
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://ting-1.appspot.com/submithandlertest", true);
xhr.onreadystatechange = function (aEvt) {
if (xhr.readyState == 4) {
if (xhr.status == 200){
console.log("request 200-OK");
chrome.browserAction.setBadgeText ( { text: "done" } );
setTimeout(function () {
chrome.browserAction.setBadgeText( { text: "" } );
}, 2000);
}else{
console.log("connection error");
chrome.browserAction.setBadgeText ( { text: "ERR" } );
}
}
};
xhr.send(formData);
}); //chrome.tabs.sendRequest
});
});
</script>
</html>
My try to unnest anonymous function and reconstruct the script:
functionForSendRequest = function (response) {var firstParagraph = response.dom;
var formData = new FormData();
formData.append("url", tab.url);
formData.append("title", tab.title);
formData.append("pitch", firstParagraph);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://ting-1.appspot.com/submithandlertest", true);
xhr.onreadystatechange = function (aEvt) {
if (xhr.readyState == 4){
if (xhr.status == 200){
console.log("request 200-OK");
chrome.browserAction.setBadgeText({text: "done" });
setTimeout(function(){
chrome.browserAction.setBadgeText({text: ""});}, 2000);}
else{console.log("connection error");
chrome.browserAction.setBadgeText({text: "ERR"});}}};
xhr.send(formData);}}
argumentToGetSelected = chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, functionForSendRequest()}
...
functionForGetSelected = function (tab) {chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, *function for getSelected goes here*)}
To see the logic clearly, instead of "unchaining" them why not just try to practice good indentation. Then you can visually follow each method according to its indentation level. Like this:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, function(response) {
var firstParagraph = response.dom;
var formData = new FormData();
formData.append("url", tab.url);
formData.append("title", tab.title);
formData.append("pitch", firstParagraph);
//formData.append("user_tag_list", "tag1, tag2");
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://ting-1.appspot.com/submithandlertest", true);
xhr.onreadystatechange = function (aEvt) {
if (xhr.readyState == 4) {
if (xhr.status == 200){
console.log("request 200-OK");
chrome.browserAction.setBadgeText ( { text: "done" } );
setTimeout(function () {
chrome.browserAction.setBadgeText( { text: "" } );
}, 2000);
} else {
console.log("connection error");
chrome.browserAction.setBadgeText ( { text: "ERR" } );
}
}
};
xhr.send(formData);
}); //chrome.tabs.sendRequest
}); // chrome.tabs.getSelected
}); // chrome.browserAction.onClicked.addListener
Or, if you want to "unchain", the only really obvious thing to do is to define that inner callback separately, like this:
var handle_request = function(response) {
var firstParagraph = response.dom;
var formData = new FormData();
formData.append("url", tab.url);
formData.append("title", tab.title);
formData.append("pitch", firstParagraph);
//formData.append("user_tag_list", "tag1, tag2");
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://ting-1.appspot.com/submithandlertest", true);
xhr.onreadystatechange = function (aEvt) {
if (xhr.readyState == 4) {
if (xhr.status == 200){
console.log("request 200-OK");
chrome.browserAction.setBadgeText ( { text: "done" } );
setTimeout(function () {
chrome.browserAction.setBadgeText( { text: "" } );
}, 2000);
} else {
console.log("connection error");
chrome.browserAction.setBadgeText ( { text: "ERR" } );
}
}
};
xhr.send(formData);
}
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {action: "getDOM"}, handle_requeest);
});
});
Related
so I'm learning about async-await in javascript and when I try to do this callback hell ( I know it is not the best practice but I have to learn It )
the second time I call the function it keeps calling itself ( infinity loop )
u can run the code to understand more cuz nothing looks wrong to me I spend the last 2 days trying to understand the problem but I end up here
code :
const xhr = new XMLHttpRequest();
const url = new URL("https://www.breakingbadapi.com/api/quotes");
const moveiData = (link, callBack) => {
xhr.addEventListener("readystatechange", () => {
if (xhr.readyState === 4 && xhr.status == 200) {
} else if (xhr.readyState === 4) {
callBack("could not fetch data");
}
});
xhr.open("GET", link);
xhr.send();
};
moveiData(url, (response) => {
console.log(response);
moveiData(url, (response) => {
console.log(response);
});
});
const url = new URL("https://www.breakingbadapi.com/api/quotes");
const moveiData = (link, callBack) => {
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", () => {
if (xhr.readyState === 4 && xhr.status == 200) {
} else if (xhr.readyState === 4) {
callBack("could not fetch data");
}
});
xhr.open("GET", link);
xhr.send();
};
moveiData(url, (response) => {
console.log(response);
});
You have three options in that issue.
1- You have added a new event listener and you should remove it when you take response.
const xhr = new XMLHttpRequest();
const url = new URL("https://www.breakingbadapi.com/api/quotes");
const moveiData = (link, callBack) => {
const handler = () => {
if (xhr.readyState === 4 && xhr.status == 200) {
xhr.removeEventListener("readystatechange", handler);
callBack(JSON.parse(xhr.response));
} else if (xhr.readyState === 4) {
callBack("could not fetch data");
}
};
const a = xhr.addEventListener("readystatechange", handler);
xhr.open("GET", link);
xhr.send();
};
moveiData(url, (response) => {
console.log(response);
moveiData(url, (response) => {
console.log(response);
});
});
2- Use onreadystatechange callback.
const xhr = new XMLHttpRequest();
const url = new URL("https://www.breakingbadapi.com/api/quotes");
const moveiData = (link, callBack) => {
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status == 200) {
callBack(JSON.parse(xhr.response));
} else if (xhr.readyState === 4) {
callBack("could not fetch data");
}
};
xhr.open("GET", link);
xhr.send();
};
moveiData(url, (response) => {
console.log(response);
moveiData(url, (response) => {
console.log(response);
});
});
3- Declare new XMLHttpRequest for every function.
const url = new URL('https://www.breakingbadapi.com/api/quotes');
const moveiData = (link, callBack) => {
const xhr = new XMLHttpRequest();
xhr.addEventListener('readystatechange', () => {
if (xhr.readyState === 4 && xhr.status == 200) {
callBack(JSON.parse(xhr.response));
} else if (xhr.readyState === 4) {
callBack('could not fetch data');
}
});
xhr.open("GET", link);
xhr.send();
};
moveiData(url, function (response) {
console.log(response);
moveiData(url, function (response) {
console.log(response);
});
});
Don't reuse the same XMLHttpRequest object. Declare a new one every time you call the function, and make sure you return some data in the callback if there's a positive response.
const url = new URL('https://www.breakingbadapi.com/api/quotes');
const moveiData = (link, callBack) => {
const xhr = new XMLHttpRequest();
xhr.addEventListener('readystatechange', () => {
if (xhr.readyState === 4 && xhr.status == 200) {
callBack(JSON.parse(xhr.response));
} else if (xhr.readyState === 4) {
callBack('could not fetch data');
}
});
xhr.open("GET", link);
xhr.send();
};
moveiData(url, function (response) {
console.log(response);
moveiData(url, function (response) {
console.log(response);
});
});
You may find the relatively new fetch API and the async/await process a little more rewarding.
const url = 'https://www.breakingbadapi.com/api/quotes';
function getData(url) {
return fetch(url);
}
async function main() {
try {
const res = await getData(url);
console.log(await res.json());
} catch (err) {
console.log(err);
}
}
main();
I have this script that I use to import some data from an API, and into my database. Since this process is very time consuming, it often times out because on some of the items processed there is a lot of data to process..
I came with this solution a while ago, using promises, to first do the request to the API, then after it finishes I would prepare the data and put it into a temporary csv file, then I would fire another request to split that file into multiple smaller files, then... you get the idea... it was working, but I need to add to it some extra requests, I just can't make it work... I probably just need to simplify my logic.
Anyone can help me improve this code to make it easier to add those extra requests and keep it sending one request after the other?
This is the (over simplified) script in question:
window.importTrialsScripts = {};
window.addEventListener('DOMContentLoaded', function() {
importTrialsScripts.app.initialize();
});
(function(importTrialsScripts, document, $) {
importTrialsScripts = importTrialsScripts || {};
const app = {
ajaxurl: 'myajaxurl',
initialize: function() {
this.submitHandler();
},
submitHandler: function() {
const self = this;
document.querySelector('#start-import').addEventListener('click', function() {
self.pullTrialsFromApi();
});
},
pullTrialsFromApi: function() {
let data = new FormData();
data.append('action', 'pull_trials_from_api');
[123, 456, 789].forEach(function(str) {
data.append('ids[]', str);
});
this.startPullingTrials(data);
},
startPullingTrials: function(data) {
const self = this;
let promise = new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if (this.status === 200) {
const response = JSON.parse(this.response);
if (! response.success) {
alert('The API could not be reached. Please try again.');
console.error('Error!!', response);
return;
}
resolve(response.data);
}
else {
console.error('there was an error in the request', this);
reject(this);
}
});
});
promise.then(function(chunks) {
const processingChunks = Object.values(chunks).map(function(chunk) {
return self.processChunk(chunk);
});
Promise.all(processingChunks).then(function (processedTrials) {
console.log('finished', processedTrials);
});
}, function(err) {
console.error('promise rejected', err);
});
},
processChunk: function(chunkTrials) {
const self = this;
let data = new FormData();
data.append('action', 'process_trials_chunk');
Object.values(chunkTrials).forEach(function(chunk) {
data.append('chunk[]', JSON.stringify(chunk));
});
return new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if (this.status === 200) {
const response = JSON.parse(this.response);
if (! response.success) {
console.error('Error!!', response.data);
return;
}
resolve(response.data);
}
else {
console.log('there was an error in the request', this);
reject(this);
}
});
});
},
splitToMultipleFiles: function() {
const self = this;
const data = new FormData();
data.append('action', 'split_location_files');
return new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if (this.status === 200) {
const response = JSON.parse(this.response);
if ( ! response.success ) {
console.error('Error!!', response.data);
return;
}
resolve(response.data.files);
}
else {
console.log('there was an error in the request', this);
reject(this);
}
});
});
},
processLocation: function(file) {
const self = this;
let data = new FormData();
data.append('action', 'process_location_data');
data.append('file', file);
return new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if ( this.status === 200 ) {
const response = JSON.parse(this.response);
if (! response.success) {
console.error('Error!!', response.data);
return;
}
resolve(response.data);
}
else {
console.log('there was an error in the request', this);
reject(this);
}
});
});
},
sendAjaxRequest: function(data, callback) {
const self = this;
let xhr = new XMLHttpRequest();
xhr.open('POST', ajaxurl);
xhr.onload = callback;
xhr.addEventListener('timeout', function(e) {
console.error('the request has timed out', e);
});
xhr.addEventListener('error', function(e) {
console.error('the request returned an error', e);
});
xhr.addEventListener('abort', function(e) {
console.error('the request was aborted', e);
});
xhr.send(data);
},
};
$.extend(importTrialsScripts, {
app: app
});
}).apply(this, [window.importTrialsScripts, document, jQuery]);
With manifest v2, I used URL.createObjectURL in order to return file from background to content. How do this with manifest v3 and Service Worker? I know about XMLHttpRequest to fetch. But what analog URL.createObjectURL?
// background.js
function onContentMessage(message, sender, sendResponse) {
if (message.action == 'requestFileGET') {
requestFileGET(message.url, (url) => sendResponse(url));
}
return true;
}
function requestFileGET(url, callback) {
let request = new XMLHttpRequest();
request.responseType = 'blob';
request.onreadystatechange = function () {
if (request.readyState == 4) {
let url = URL.createObjectURL(request.response);
callback(url);
}
};
request.open('GET', url);
request.send();
}
// content.js
backgroundFileGET(urlCover, (cover) => {
let url = `${HANDLER_UPLOADPIC}?kind=${kind}&sign=${sign}`;
let formData = new FormData();
formData.append('file', cover);
requestFilePOST(url, formData, callback);
});
function backgroundFileGET(url, callback) {
backgroundRequest('requestFileGET', url, (backgroungdUrl) => {
requestFileGET(backgroungdUrl, (file) => callback(file));
});
}
function backgroundRequest(action, url, callback) {
chrome.runtime.sendMessage({ action: action, url: url }, (response) => callback(response));
}
My Solution Store the data with a ID and open a new tab with a page like download.html#ID
let videoId = '#' + new Date().valueOf();
self.DownloadedVideoData[videoId] = { data: data, filename:
filename, mimetype:mimetype, segment:segment, action:'download' };
chrome.tabs.create({ url: "video.html" + videoId, active: false });
Inside the Page register a function to onload and your downloading Code
chrome.runtime.sendMessage({
action: 'GetVideoDataByID',
VideoID: self.VideoID,
}, function (videoData) {
if (videoData.action == 'download') self.DownloadVideo(videoData);
);
self.DownloadVideo = function (request) {
let blob = new Blob(request.data, { type: request.mimetype }),
downloadId;
chrome.downloads.onChanged.addListener(function (dl) {
if (dl.id === downloadId && dl.state && dl.state.current ==
'complete') {
window.close();
}
});
chrome.downloads.download({
url: URL.createObjectURL(blob),
filename: request.filename
}, function (id) {
downloadId = id;
window.close();
});
}
Now you need only a Listener in your Backround Worker like that
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
switch (request.action) {
case 'GetVideoDataByID':
sendResponse(self.GetVideoDataByID(request.VideoID));
break;
default:
break;
}
}
I want to convert a jquery function into a javascript function:
window.parent.$.ajax({
type: 'GET',
url: "http://localhost:3063/corsService/GetCultureInformation",
contentType: "application/json",
dataType: "json",
success: function (data) {
numberDecimalDigit = data.NumberDecimalDigits;
},
async: false
});
I converted it to:
var request = new XMLHttpRequest();
request.open('GET', 'http://localhost:3063/corsService/GetCultureInformation', false);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
// Success!
numberDecimalDigit = data.NumberDecimalDigits;
var resp = this.response;
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
but I have errors:
1: XMLHttpRequest: Network Error 0x2efd, Could not complete the operation due to error 00002efd.
2: NetworkError
//Better use promises, as it reduces biolerplate heavy code of XMLhttp request provides.
function loadjson(file) {
return new Promise((resolve, reject) => {
return fetch(file).then((response) => {
if (response.ok) {
resolve(response.json());
} else {
reject(new Error("error"));
}
});
});
}
var newFile=loadjson("https://api.postalpincode.in/pincode/110001").then((data) => {
console.log(data);
});
I'm trying to call ajax request without using jquery. By using ECMA Script6:
var promise1 = new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
var url = urls.urlListChapters.replace(0, specificationId);
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
if (xhr.status === 200) {
alert(xhr.response);
resolve(xhr.response);
} else {
reject(new Error(xhr.statusText));
}
};
xhr.onerror = function() {
reject(new Error("Network error"));
};
xhr.send();
});
promise1.then(function(data) {
alert('Your public IP address is: ' + data);
}, function(status) {
alert('Something went wrong.');
});
I get as response "null". However, with my ol jquery method, I do get the list of objects.
$.ajax({
url: urls.urlListChapters.replace(0, specificationId),
dataType: 'json',
method: 'GET',
})
.done(function(data) {
var data = JSON.parse(data);
console.log(data);
alert(1)
})
.fail(function(jqXHR, textStatus, errorThrown){
console.log(jqXHR);
alert('WHAT!');
});
Is there something I'm missing?