With jQuery.when()
, if one request fails then they all fail.
$.when(deferred1, deferred2).then(function() {
// Called only after both deferred are resolved
}, function() {
// Called immediately after one of the deferreds is rejected
});
How can you wait for everything to execute even failures? I tried to use .always()
instead of .then()
but the callback is also being called right after the first failure.
One (ugly) solution would be to have flags to control when both operations are completed and use the .always()
on each of them (without $.when()
).
var deferred1Complete = false;
var deferred2Complete = false;
function callback() {
if (deferred1Complete && deferred2Complete) {
// Execute after both deferred are either resolved or rejected
}
}
deferred1.always(function() {
deferred1Complete = true;
callback();
});
deferred2.always(function() {
deferred2Complete = true;
callback();
});
Is there a better way to do this?
Jonatan,
I like your solution and offer a few improvements to :
Here's the code :
(function($) {
$.whenAlways = function(chain) {
if(!chain || !$.isArray(chain)) chain = $.extend([], arguments);
var n = chain.length;
return $.Deferred(function(deferred) {
$.each(chain, function(i, promise) {
if(!promise.always) n--;
else {
promise.always(function() {
deferred.notify(--n);
if(n == 0) deferred.resolve();
});
}
});
if(n == 0) deferred.resolve();
}).promise();
}
})(jQuery);
This approach would allow any progressCallbacks (added to the retuned promise) to be called whenever a chain
promise is reolved/rejected, regardless of reolution/rejection order. By passing the number of outstanding chain
promises to the progressCallbacks, you could, for example, provide a countdown indication or respond to intermediate countdown milestones.
Seems to work - DEMO