Returning value after async function [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I can't get my head around how to return the value from uniqueCheck() to isValid. I've added in a setTimeout to simulate the async operation.
function isValid(data) {
uniqueCheck(data, function(val) {
return val;
//true
});
// need the value here
}
function uniqueCheck(data, cb) {
// do something with data async
setTimeout(function () {
cb(true)
}, 1000);
}
console.log(isValid("some data"));

To use asynchronous calls in your code you can use Promises or for example if you use jQuery you can make use of Deferred object.
//async function using $.Deferred
function asyncFunction(){
var dd = $.Deferred();
setTimeout(function(data) {
dd.resolve('loaded');
}, 500);
return dd.promise();
}
//somwhere in your code
asyncFunction().then(function(value){
//do stuff when Deferred object is resolved
//value = 'loaded'
})
in your code:
function isValid(data) {
uniqueCheck(data).then(function(){
//value is available here
});
// but not here
//because this code is executed earlier then callback
}
function uniqueCheck(data, cb) {
var dd = $.Deferred();
// do something with data async
setTimeout(function () {
cb(true)
}, 1000);
return dd.promise();
}

you have to return the result through an callback function
function isValid(data, callback) {
uniqueCheck(data, function(val) {
callback(true);
return val;
//true
});
// need the value here
}
function uniqueCheck(data, cb) {
// do something with data async
setTimeout(function () {
cb(true)
}, 1000);
}
//console.log(isValid("some data"));
isValid("some data", function(value){
console.log(value);
});

Related

callback function returning undefined [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I'm trying to return an object inside a callback function
In the following situation, the console.log() show the result as expected
var dVizModule = (function(){
let dataset;
function loadData(fileName) {
dataset = d3.csv(fileName, (data) => {
dataset = data;
console.log(dataset);
});
};
return {
loadData: loadData
}
})();
dVizModule.loadData("data/time_scale_data.csv")
but when I try to use return in callback function the story is different and it returns undefined
var dVizModule = (function(){
let dataset;
function loadData(fileName) {
dataset = d3.csv(fileName, (data) => {
dataset = data;
return dataset;
});
// return dataset; or even here!
};
return {
loadData: loadData
}
})();
console.log(dVizModule.loadData("data/time_scale_data.csv"))
Since its a callback based workflow, the code above won't work. d3.csv is an asynchronous function, you can only get the result through a callback passed to it and hence even loadData needs to follow the same pattern.You just need to write something like this.
var dVizModule = (function(){
function loadData(fileName,callback) {
d3.csv(fileName, (data) => {
callback(data);
});
};
return {
loadData: loadData
}
})();
dVizModule.loadData("data/time_scale_data.csv",(data)=>{
console.log(data);
})

JavaScript sequential async function calls

I have an array of functions, which making some logic asynchronously (e.g. ajax calls). How does look like function, which will sequentially call functions from array?
var saveHandlers = [];
saveHandlers.push(function () {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve();
}, 2000);
return deferred.promise();
});
saveHandlers.push(function () {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve();
}, 2000);
return deferred.promise();
});
$(function () {
var $form = $('#form');
$form
.unbind('submit')
.submit(function (e) {
if (saveHandlers.length > 0) {
$.when.apply(null, saveHandlers);
}
e.preventDefault();
});
});
Write a function which calls you async function and takes the array index as an argument.
In the callback for the async function, increment the index and (if you haven't got to the end of the array) call the function recursively with the new index.
var foo = [fun_a, fun_b, fun_c];
function bar(index) {
index = index || 0;
function callback() {
if (foo[++index]) {
bar(index);
}
};
foo[index]().then(callback);
}

How can I perform an async operation in $.Deferred.then failFilter callback and pass back to success chain? [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
the following will pass flow back to success chain after handling error:
asyncThatWillFail().then(null, function () {
//handle error
return $.Deferred().resolve();
}).then(nextSuccessCallback);
In my particular scenario though, I need to perform multiple parallel async operations in the error handler using the $.when.apply($, promises) approach:
asyncThatWillFail().then(null, function () {
var promises = [];
for (var i = 0; i < 3; i++) {
var dfd = $.Deferred();
setTimeout(function () {
dfd.resolve();
}, 1000);
promises.push(dfd.promise());
}
return $.when.apply($,promises);
}).then(nextSuccessCallback);
I had assumed the above would work since I am returning promise that would eventually be resolved. This jsFiddle though shows that after going through my error handler, neither the following success or error callback are called.
Since the action in the error handler is async, I can't just go ahead and send some resolved value through the return. Not sure where to go from here.
Your issue now is closure ... only the last created promise in the loop of 3 will be resolved due to closure
asyncThatWillFail().then(null, function () {
log("error handler");
var promises = [];
for (var i = 0; i < 3; i++) {
(function() { // IIFE for a closure
var dfd = $.Deferred();
setTimeout(function () {
dfd.resolve();
}, 1000);
promises.push(dfd.promise());
}());
}
return $.when.apply(null,promises);
}).then(nextSuccessCallback, nextFailCallback);
function asyncThatWillFail () {
var dfd = $.Deferred();
setTimeout(function(){
dfd.reject();
}, 1000)
return dfd.promise();
}
function nextSuccessCallback () {
log("success");
}
function nextFailCallback () {
log("failure");
}
function log (msg) {
$("#logger").append("<p>"+msg+"</p>");
}
see updated fiddle

JavaScript - Using return argument of function that has AJAX call [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I have the following function in javascript:
function checkFunc(msg) {
$.getJSON("myurl.php", {
dtccode: msg
}, function(j) {
return j.boolField;
}); //JSON call
}
And I call it in another function:
function check(msg) {
var ret = checkFunc1(); //some other function
ret = checkFunc2() && ret; //some other function
ret = checkFunc3() && ret; //some other function
ret = checkFunc() && ret;
if (ret) {
//code
}
}
My problem is, that I know the checkFunc should return false, but it returns true. I think this may be a synchronization issue, but I don't know what to do.
Can anyone help?
AJAX is asynchronous. Means that you have to use callback function to get the result. Like so:
function checkFunc(msg, callback) {
$.getJSON("myurl.php", {
dtccode: msg
}, function(j) {
callback(j.boolField);
}); //JSON call
}
and
function check(msg) {
checkFunc(msg, function(result){
alert(result);
});
}
EDIT: Using deferred system:
$.getJSON("myurl.php").done(function(j) {
callback(j.boolField);
});
You can also add fail() to check for possible error. Check the docs: http://api.jquery.com/jquery.getjson/

Chaining ajax requests with jQuery's deferred

I have a web app which must call the server multiple times. So far, I had a long nested callback chain; but I would like to use jQuery's when,then etc. functionality. However, I can't seem to get stuff running again after using a then.
$
.when ($.get('pages/run-tool.html'))
.then (function (args)
{
// This works fine
alert(args);
$('#content').replaceWith (args);
$('#progress-bar').progressbar ({value: 0});
})
.then ($.get('pages/test.html'))
.done (function(args)
{
// This prints the same as the last call
alert (args);
});
What am I doing wrong? I guess its some scoping issue, as I can see the second get call being executed. Using two different args variables does not help as the argument passed to the done function is still the first get request.
As an update:
With modern jquery (1.8+) you don't need the preliminary when because get returns a Deferred Promise.
Also, pipe is deprecated. Use then instead. Just be sure to return the result of the new get which becomes the Promise attached to by subsequent then/*done*/fail calls.
So:
$.get('pages/run-tool.html')
.then (function (args) { // this will run if the above .get succeeds
// This works fine
alert(args);
$('#content').replaceWith (args);
$('#progress-bar').progressbar ({value: 0});
})
.then (function() { // this will run after the above then-handler (assuming it ran)
return $.get('pages/test.html'); // the return value creates a new Deferred object
})
.done (function(args) { // this will run after the second .get succeeds (assuming it ran)
alert (args);
});
All three callbacks (the two with then and the one with done) are applied to the same request – the original when call. This is because then returns the same Deferred object, rather than a new one, so that you can add multiple event handlers.
You need to use pipe instead.
$
.when ($.get('pages/run-tool.html'))
.then (function (args)
{
// This works fine
alert(args);
$('#content').replaceWith (args);
$('#progress-bar').progressbar ({value: 0});
})
.pipe (function() {
return $.get('pages/test.html'); // the return value creates a new Deferred object
})
.done (function(args)
{
alert (args);
});
Here is an wonderfully simple and highly effective AJAX chaining / queue plugin. It will execute you ajax methods in sequence one after each other.
It works by accepting an array of methods and then executing them in sequence. It wont execute the next method whilst waiting for a response.
//--- THIS PART IS YOUR CODE -----------------------
$(document).ready(function () {
var AjaxQ = [];
AjaxQ[0] = function () { AjaxMethod1(); }
AjaxQ[1] = function () { AjaxMethod2(); }
AjaxQ[3] = function () { AjaxMethod3(); }
//Execute methods in sequence
$(document).sc_ExecuteAjaxQ({ fx: AjaxQ });
});
//--- THIS PART IS THE AJAX PLUGIN -------------------
$.fn.sc_ExecuteAjaxQ = function (options) {
//? Executes a series of AJAX methods in dequence
var options = $.extend({
fx: [] //function1 () { }, function2 () { }, function3 () { }
}, options);
if (options.fx.length > 0) {
var i = 0;
$(this).unbind('ajaxComplete');
$(this).ajaxComplete(function () {
i++;
if (i < options.fx.length && (typeof options.fx[i] == "function")) { options.fx[i](); }
else { $(this).unbind('ajaxComplete'); }
});
//Execute first item in queue
if (typeof options.fx[i] == "function") { options.fx[i](); }
else { $(this).unbind('ajaxComplete'); }
}
}
The answer cdr gave, which has the highest vote at the moment, is not right.
When you have functions a, b, c each returns a $.Deferred() object, and chains the functions like the following:
a().then(b).then(c)
Both b and c will run once the promise returned from a is resolved. Since both then() functions are tied to the promise of a, this works similiar to other Jquery chaining such as:
$('#id').html("<div>hello</div>").css({display:"block"})
where both html() and css() function are called on the object returned from $('#id');
So to make a, b, c run after the promise returned from the previous function is resolved, you need to do this:
a().then(function(){
b().then(c)
});
Here the call of function c is tied to the promise returned from function b.
You can test this using the following code:
function a() {
var promise = $.Deferred();
setTimeout(function() {
promise.resolve();
console.log("a");
}, 1000);
return promise;
}
function b() {
console.log("running b");
var promise = $.Deferred();
setTimeout(function () {
promise.resolve();
console.log("b");
}, 500);
return promise;
}
function c() {
console.log("running c");
var promise = $.Deferred();
setTimeout(function () {
promise.resolve();
console.log("c");
}, 1500);
return promise;
}
a().then(b).then(c);
a().then(function(){
b().then(c)
});
Change the promise in function b() from resolve() to reject() and you will see the difference.
<script type="text/javascript">
var promise1 = function () {
return new
$.Deferred(function (def) {
setTimeout(function () {
console.log("1");
def.resolve();
}, 3000);
}).promise();
};
var promise2 = function () {
return new
$.Deferred(function (def) {
setTimeout(function () {
console.log("2");
def.resolve();
}, 2000);
}).promise();
};
var promise3 = function () {
return new
$.Deferred(function (def) {
setTimeout(function () {
console.log("3");
def.resolve();
}, 1000);
}).promise();
};
var firstCall = function () {
console.log("firstCall");
$.when(promise1())
.then(function () { secondCall(); });
};
var secondCall = function () {
console.log("secondCall")
$.when(promise2()).then(function () { thirdCall(); });
};
var thirdCall = function () {
console.log("thirdCall")
$.when(promise3()).then(function () { console.log("done"); });
};
$(document).ready(function () {
firstCall();
});
</script>
I thought I would leave this little exercise here for anyone who may find it useful, we build an array of requests and when they are completed, we can fire a callback function:
var urls = [{
url: 'url1',
data: 'foo'
}, {
url: 'url2',
data: 'foo'
}, {
url: 'url3',
data: 'foo'
}, {
url: 'url4',
data: 'foo'
}];
var requests = [];
var callback = function (result) {
console.log('done!');
};
var ajaxFunction = function () {
for (var request, i = -1; request = urls[++i];) {
requests.push($.ajax({
url: request.url,
success: function (response) {
console.log('success', response);
}
}));
}
};
// using $.when.apply() we can execute a function when all the requests
// in the array have completed
$.when.apply(new ajaxFunction(), requests).done(function (result) {
callback(result)
});
My way is to apply callback function:
A(function(){
B(function(){
C()})});
where A, B can be written as
function A(callback)
$.ajax{
...
success: function(result){
...
if (callback) callback();
}
}

Categories