Still have problems with this. When I call this function it appears to return twice??? I get 'test2' in the console followed by 'test'. I also put the callback return value into the console and its false then true. The getwidget is only called once from this.nextwidget which is a button.
getwidget = function (callback) {
var id = get_name_value('salesperson');
var password = 'password';
if (id !== "") {
$.get('http://somewhere.com?id=' + id + '&password=' + password,
function (data, status) {
console.log(status);
if (status === 'success') {
catalogue = $.parseJSON(data);
if (catalogue.status === "error") {
alert(catalogue.message);
} else {
console.log('test');
if (callback) callback(true);
}
} else {
alert("Error connecting to API:" + status);
}
});
}
console.log('test2');
if (callback) callback(false);
};
this.nextwidget = function() {
catindex = catindex + 1;
getwidget(function(trigger) {
if (!trigger && catindex > 0) {
catindex = catindex - 1;
}
if (catindex === catlen - 1) {
document.getElementById("nextwidget").disabled = true;
}
if (catindex !== 0) {
document.getElementById("prevwidget").disabled = false;
}
console.log(catindex);
console.log(trigger);
});
};
Javascript is asynchronous.
$.get operation is asynchronous, because it is a call to the server.
It means that JS is not waiting till the end of this operation and just continuing excuting next block of code.
So, according to your code, it shows 'test2' in a console, than executes callback with false parameter. And only when response from server received, it shows "test" in console and run callback with true parameter.
(certainly, if request was successful, according to your snippet)
Here is simple jsfiddle for better understanding how it works.
Simple async example
function asyncExample() {
setTimeout(function() {
console.log('test');
}, 1000);
console.log('test2')
}
asyncExample();
Because operation in timeout is delayed (like asynchronous), JS will not wait and just continue with next lines. So the result will be:
'test2' first and then 'test'.
Related
Thanks for taking a look at this. I am making an api call with recursion to check on a task status update. I had implemented this function last week, and it was working?? Not sure why it doesn't anymore. The conditional that doesn't work is if the status is a FAILURE, it doesn't clearout the timeout, but it does enter the conditional.... Timeout is declared outside the function in the correct context.
export async function exponentialBackoff (checkStatus, task_id, timeout, max, delay, callback) {
let status = await checkStatus(task_id);
if (status === "SUCCESS") {
callback();
} else {
if (status === "PENDING") {
timeout = setTimeout(function() {
return exponentialBackoff(checkStatus, task_id, timeout, --max, delay * 2, callback);
}, delay);
} else if (status === "FAILURE" || max === 0){
clearTimeout(timeout);
return "FAILURE";
}
}
}
It looks like a callback hell. I would strongly recommend you to avoid name shadowing and overwriting the arguments.
Also - I believe you don't want to keep the previous timeout alive if a next one was called?
let timeoutInstance;
const clear = (tm) => {
if (tm) clearTimeout(tm);
};
export async function exponentialBackoff (checkStatus, task_id, max, delay, callback) {
let status = await checkStatus(task_id);
if (status === "SUCCESS") {
callback();
} else {
if (status === "PENDING") {
clear(timeoutInstance);
timeoutInstance = setTimeout(function() {
return exponentialBackoff(checkStatus, task_id, --max, delay * 2, callback);
}, delay);
} else if (status === "FAILURE" || max === 0){
clear(timeoutInstance);
return "FAILURE";
}
}
}
I have a standard function that successfully checks to see if a particular app is installed. But that function takes a few moments to execute and I need to bind it into a promise.then(function (response) { ...} because the app checker takes too long to execute...causing an async issue with the intended response from the app check function. But I can't get it work.
checkSocialApp only returns a true or false:
function checkSocialApp(objApp) {
if (device.platform == "iOS") {
var scheme = objApp.ios;
} else {
var scheme = objApp.and;
}
if (objApp.appName == "Facebook") {
return true ; // FB doesn't need app, can be logged in via browser
} else {
return appAvailability.check(
scheme,
function() { // success callback
console.log(scheme + " is Installed") ;
return true ;
}, function () { // Error callback
console.log(scheme + " is NOT Installed") ;
alert("You do not have the " +objApp.appName+ " app installed.") ;
return false ;
}
);
}
checkSocialApp(appObj).then(function(response){ // errors on 'then'
if (response == true) { // app IS installed
console.log("CheckApp True") ;
appObj.loginApp() ;
} else if (response == false) { // app IS NOT installed
console.log("CheckApp False") ;
appObj.disableApp() ;
}
}) ;
The above errors out on the .then. So I try to bind it to a promise.resolve:
var promise1 = Promise.resolve(checkSocialApp(appObj)) ;
promise1.then(function(response) {
if (response == true) ...
This executes the checkSocialApp function successfully (as I see proper console messages printing from within that function), but I am not getting the response back into the remaining part of the .then for processing.
You have to do something like this return a promise in your function:
function checkSocialApp(objApp) {
return new Promise( function(resolve)={
if (device.platform == "iOS") {
var scheme = objApp.ios;
} else {
var scheme = objApp.and;
}
if (objApp.appName == "Facebook") {
resolve (true) ; // FB doesn't need app, can be logged in via browser
} else {
return appAvailability.check(
scheme,
function() { // success callback
console.log(scheme + " is Installed") ;
resolve (true) ;
}, function () { // Error callback
console.log(scheme + " is NOT Installed") ;
alert("You do not have the " +objApp.appName+ " app installed.") ;
resolve (false) ;
}
);
}
})
}
checkSocialApp(appObj).then(function(response){ // errors on 'then'
if (response == true) { // app IS installed
console.log("CheckApp True") ;
appObj.loginApp() ;
} else if (response == false) { // app IS NOT installed
console.log("CheckApp False") ;
appObj.disableApp() ;
}
}) ;
Does checkSocialApp usually take a callback? You can wrap it in a promise like this:
function checkSocialAppPromise ( appObj ) {
return new Promise( function ( resolve ) {
checkSocialApp( appObj, resolve )
});
}
What you have should work, strictly speaking. If checkSocialApp(appObject) returns true or false, then you should get it. What you show works. If it isn't, then there must be something odd going on.
const someFunc = () => 5;
Promise.resolve(someFunc()).then(result => console.log(result));
However, it probably won't do what you are trying to do. You can't magically make a long-running synchronous function run async.
For example, if I have this function:
function runSlow() {
const start = Date.now();
while (Date.now() - start < 5000) { } // force a loop to wait 5 seconds
return true;
}
runSlow();
console.log('done');
Which takes 5 seconds to complete. I can't just wrap it up and make it asynchrnous suddenly:
function runSlow() {
const start = Date.now();
while (Date.now() - start < 5000) { } // force a loop to wait 5 seconds
return true;
}
Promise.resolve(runSlow())
.then(response => console.log(response));
While technically it is wrapped in a promise, it still takes 5 seconds to run and it still blocks things (try clicking while it's running and you'll see your browser is unresponsive).
If you want it to run properly, you'll have to modify the function itself to stop being synchronous all together. There isn't any way to just wrap it up in it's own thread or anything.
I have a function that is checking for a stored value through chrome.storage.sync.get and inserting a CSS file upon existence of said stored value.
I realize chrome.storage.sync.get is an async function and the return value is not passing back as expected to the makeAggressive() function. However, I don't know how else to write this code to get the result of if (result == 'aggressive') passed to makeAggressive().
How can I retrieve the stored value, check its value and return the result to the calling function?
chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
if (info.status == 'complete') applyCSS(tab);
});
function applyCSS(tab) {
var tabUrl = tab.url;
if (makeAggressive()) {
chrome.tabs.insertCSS(tab.id, {
file: "aggressive.css"
});
}
}
function makeAggressive() {
chrome.storage.sync.get(function(items) {
var result = items.intensityLevel;
if (result == 'aggressive') {
return true;
}
});
}
Simply pass a callback into the async function.
The callback shall be called once the asynchronous activity is completed.
async_function(function() {
// do something after async_function completes and invokes this callback
});
function async_function(callback) {
something_async(function(result) {
callback(result);
});
}
In your case:
function applyCSS(tab) {
var tabUrl = tab.url;
makeAggressive(function() {
chrome.tabs.insertCSS(tab.id, {
file: "aggressive.css"
});
});
}
function makeAggressive(callback) {
chrome.storage.sync.get(function(items) {
var result = items.intensityLevel;
if (result == 'aggressive') {
callback();
}
});
}
In an $.ajax callback, I want to do something depending on what I receive from the server, which is sending true or false.
The problem is, somewhere in the code, I want a return to fire and it doesn't :
function check()
{
// $.ajax callback(result)
{
console.log(result); //in this case I get 'true' (boolean)
if(!result)
{
// I checked I don't end up here
}
else
{
console.log('well done'); // shows up in the console
return "done";
}
}
return "oops";
}
// later in the code
console.log(check()); // displays "oops" whereas the console.log('well done') has showned up in the console
Parts of the function I didn't give you are mostly CSS effects.
Do you have any idea why a return couldn't fire, or what did I miss ? Thanks in advance !
You are returning a value in a callback, this is why you don't get this value, your code is equivalent to:
function callback (result) {
if (!result) { }
else {
console.log('well done') ;
return "done";
}
}
function _ajax (cb) {
cb (true) ; // Call cb but does not care about the result
return true ;
}
function check() {
ajax (callback) ; // Call ajax but does not care about its result
return "oops";
}
check () ;
If you were doing an asynchronous request, the behaviour would be a bit different, but the idea would remain the same.
You should never do synchronous (a)jax calls, but if you did not care, you could do the following:
function check () {
var res ;
$.ajax ({
success: function (result) {
if (!result) { res = "fail" ; }
else {
console.log('well done') ;
res = "done" ;
}
}
}) ;
return (typeof res === 'undefined') ? "oops" : res ;
}
My foreach loop:
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
if(deleteQuoteItemFromListing(jQuery(this).attr('data-id'))){
console.log('passed');
}else{
console.log('failed');
}
}
});
And the function is(It's using prototype) but it successes
function deleteQuoteItemFromListing(id){
//does someoperations and on success
delurl = getDelUrl()+id; //baseurl/module/action/delete/id
new Ajax.Request(delurl,{
method: 'get',
onSuccess: function(transport){
return TRUE;
}
})
}
but the problem is all foreach executes at once, and doesn't wait for response from function. It prints failed even the operation is success.
Updated
The other way round i tried first is this
jQuery('.delete-from-quote').click(function() {
var i = 0, j = 0;
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
i++;
}
});
if (i == 0) {
alert('please choose product');
return false;
}
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
var urlData = "<?php echo $this->getUrl('qquoteadv/index/delete/'); ?>";
urlData += "id/" + jQuery(this).attr('data-id') + "/"
var ajax = jQuery.ajax({
type: "GET",
url: urlData,
success: function(msg) {
j++;
}
})
}
if(i==j){location.reload();} //after completing all, reload the page
});
});
The problem is to know all action completed and reloading the page.
My guess is that the code you've omitted is doing an asynchronous ajax call. Since ajax is asynchronous by default, the code you write there ($.ajax or whatever) starts the process, but then the process continues in the background while your code continues to run.
There's no reasonable way to make the deleteQuoteItemFromListing function wait for the response. (While it's possible to do synchronous ajax, A) it makes for a poor user experience by locking up the browser UI, and B) jQuery will be removing that option at some stage, forcing you to go direct to XHR if you want to keep doing it.)
Instead, restructure your code to embrace the asynchronous nature of web programming by having your function either return a promise or accept a callback, and then resolve the promise or call the callback when done.
Here's a rough idea of what the promise version would look like:
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
deleteQuoteItemFromListing(jQuery(this).attr('data-id'))
.done(function(id) {
console.log(id + ' passed');
})
.fail(function(id) {
console.log(id + ' failed');
});
}
});
function deleteQuoteItemFromListing(id){
var d = jQuery.Deferred();
jQuery.ajax(/*...*/)
.done(function() { // This bit assumes the deletion worked if
d.resolveWith(id); // the ajax call worked, and failed if the
}) // ajax call failed; if instead the ajax
.fail(function() { // call always works and returns a flag,
d.rejectWith(id); // adjust accordingly
});
return d.promise();
}
Using callback ensures that the function is executed.
jQuery(".custom-checkbox").each(function () {
if (jQuery(this).attr('data-action') == 'true') {
deleteQuoteItemFromListing(jQuery(this).attr('data-id'), handleData);
}
});
function handleData(data) {
if (data) {
console.log('passed');
} else {
console.log('failed');
}
}
function deleteQuoteItemFromListing(id, callback) {
//does someoperations and on success
delurl = getDelUrl() + id; //baseurl/module/action/delete/id
new Ajax.Request(delurl, {
method: 'get',
onSuccess: function (transport) {
callback(true);
}
})
}
I hope this will work for you. you need to define handleData function outside of the other function.
Use jquery When.
You need to queue those Deferred in an array of Deferred and then apply all of the functions at once.
If one fails all will fail and if all succeeds all will pass.
check this out jQuery When
var queue = [];
var items = 0;
return new $.Deferred(function (deferred) {
$(".custom-checkbox").each(function () {
if ($(this).attr('data-action') == 'true') {
items++;
queue.push(function () {
new Ajax.Request(delurl, {
method: 'get',
onSuccess: function (transport) {
items--;
if(items === 0)
deferred.resolve();
},
onError:function(e){
deferred.reject(e);
}
});
});
}
});
//now resolve all of the deferred fns
$.when(queue).done(function(){
console.log('All went well');
})
.fail(function(e){
console.log('Error ' + e);
});
});
(Part of) Your problem is in this simple statement:
return TRUE;
In JavaScript, the "true" boolean is written in lowercase:
return true;
The interpreter thinks TRUE is a variable, and will throw a ReferenceError, since it's not set / defined anywhere, meaning the function will never return true.