I cannot get the done/fail/always callbacks on each of my ajax requests to execute before the deferred object's callbacks.
The problem I have is that some of my ajax requests may fail, but I need to execute the same code whether one fails or none fail.
Hard to explain exactly, so I made this fiddle to help show the problem I am having. http://jsfiddle.net/zZsxV/
var a1 = $.Deferred();
var a2 = $.Deferred();
var a3 = $.Deferred();
a1.done(function() {
$('body').append('a1 done<br />');
}).fail(function() {
$('body').append('a1 fail<br />');
}).always(function() {
$('body').append('a1 always<br />');
});
a2.done(function() {
$('body').append('a2 done<br />');
}).fail(function() {
$('body').append('a2 fail<br />');
}).always(function() {
$('body').append('a2 always<br />');
});
a3.done(function() {
$('body').append('a3 done<br />');
}).fail(function() {
$('body').append('a3 fail<br />');
}).always(function() {
$('body').append('a3 always<br />');
});
var def = $.when(a1, a2, a3);
def.always(function() {
$('body').append('defer always <-- should be after all<br />');
});
setTimeout(function() {
a1.resolve();
}, 5000);
setTimeout(function() {
a2.reject();
}, 1000);
setTimeout(function() {
a3.resolve();
}, 3000);
I read a lot of the answers on this topic but I don't believe any fit my need exactly.
Any more information needed to help please let me know and I'll add it once I get back. Thanks in advance.
I do understand what is happening. I just know how to do it to avoid this problem. I tried using .then as well with the same results. Once one request is rejected, it fires the fail callback before waiting for the other callbacks.
According to jQuery documentation $.when
fires callbacks when either all of parameters are resolved or one of them is rejected. So how about using something like that instead of $.when
:
var custom_when = function() {
var args = $.makeArray(arguments);
var callback = args.pop();
var all = [];
$.each(args, function(index, def) {
def.always(function() {
var idx = all.indexOf(def);
if (idx !== -1) {
all.splice(idx, 1);
}
if (!all.length) {
callback();
}
});
all.push(def);
});
};
and you can use it like that:
custom_when(a1, a2, a3, function() {
// do some stuff.
});
and jsFiddle demo.
I see what you are trying to do here, but there is no convenient method. This works:
JSFIDDLE
$.when(a1).done(a2).done(a3).then(function() {
$('body').append('defer always <-- should be after all<br />');
});
Other option would be to write your own simple function. See updated FIDDLE:
whenAllResolved(a1, a2, a3).done(function () {
$('body').append('defer always <-- should be after all<br />');
});
function whenAllResolved(){
var d = $.Deferred(),
args = arguments,
verifyDeferreds = function(){
var allResolved = true;
$.each(args, function(i, arg){
if(arg.state() === 'pending'){
allResolved = false;
return false;
}
});
if (allResolved){
d.resolve();
}
};
$.each(arguments, function(i, arg){
arg.always(verifyDeferreds);
});
verifyDeferreds();
return d;
}
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