I am trying to figure out a way to wait for multiple deferred objects and process them once done, may be like to start next set for deferred objects.
I am stuck because the result of the following is not the it is expected to be. I am expecting the result as
allDone resovled values are 1,2,3
The actual result is
allDone resovled values are 1,2
var dfd1 = new $.Deferred();
var dfd2 = new $.Deferred();
var dfd3 = new $.Deferred();
var dfds = [ dfd1, dfd2, dfd3 ];
var resolvedValues = [];
$.when.apply($, dfds).done(function() {
dfds.forEach(function(dfd){
console.log("inloop");
dfd.promise().done(function(value) {
resolvedValues.push(value);
});
});
console.log("allDone resovled values are" + resolvedValues);
})
dfd1.resolve(1);
dfd2.resolve(2);
dfd3.resolve(3);
For the why, see below. But you're overcomplicating it. :-) The callback you give the final promise you get from when
gives you the resolved values as arguments:
$.when.apply($, dfds).done(function(a, b, c) {
// Here, a is 1, b is 2, c is 3
// Or you can access them on `arguments`
})
Live Example:
var dfd1 = new $.Deferred();
var dfd2 = new $.Deferred();
var dfd3 = new $.Deferred();
var dfds = [ dfd1, dfd2, dfd3 ];
var resolvedValues = [];
$.when.apply($, dfds).done(function() {
// Use a trick to turn `arguments` into a real array
var a = Array.prototype.slice.call(arguments);
// Show what we got
console.log("allDone: " + a.join(", "));
})
dfd1.resolve(1);
dfd2.resolve(2);
dfd3.resolve(3);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Side note: I assume you're dealing with an array on purpose. If you have a fixed number of promises you need to wait on, just use the simpler form
$.when(dfd1, dfd2, dfd3).then(function(a, b, c) {
// ...
});
Here's why you're getting the very odd result you're getting: jQuery's Deferred
/Promise
objects have a problem in that they are chaotic: When you call done
on them, you don't know whether your callback will be executed synchronously or asynchronously. This is a serious flaw, and one that a true Promises/A+ implementation does not have (the callback is always asynchronous).
jQuery will call the callback asynchronously if the promise is not yet resolved. But it will call it synchronously if it isn't resolved:
var d1 = $.Deferred();
d1.done(function() {
console.log("I'm called asynchronously");
});
d1.resolve();
var d2 = $.Deferred();
d2.resolve();
d2.done(function() {
console.log("I'm called synchronously");
});
So what's happening in your code is that the overall done
callback that when
fires is fired during the done
callback on the last promise that got resolved (dfd3
). Since the promise isn't marked resolved until after the done
callbacks have been completed, when your code runs, dfd1
and dfd2
are resolved but dfd3
is still in the process of being resolved. So your inner callbacks are called synchronously for dfd1
and dfd2
but asynchronously for dfd3
. So you're outputting your result before the dfd3
return value has been pushed onto your array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With