jquery deferred - "always" called at the first reject

javascript, jquery, jquery-deferred

Solution

It's by design: The method will resolve its master Deferred as soon as all the Deferreds resolve, or reject the master Deferred as soon as one of the Deferreds is rejected. [...] Note that some of the Deferreds may still be unresolved at that point.

http://api.jquery.com/jQuery.when/

You can save references to all deferreds and track them separately.

Something like this:

var whenAll = function() {
   var dfd = $.Deferred(),
       len = arguments.length,
       counter = 0,
       state = "resolved",
       resolveOrReject = function() {
           if(this.state() === "rejected"){
               state = "rejected";
           }
           counter++;

           if(counter === len) {
               dfd[state === "rejected"? "reject": "resolve"]();   
           }

       };


    $.each(arguments, function(idx, item) {
        item.always(resolveOrReject); 
    });

   return dfd.promise();    
};

http://jsfiddle.net/cSy2K/2/

Problem

I'm using `$.when` to chain some Deferred objects, and if one of them fail, the `always` method will be called directly after the failure, even if I still have some deferrer in a "pending" state. ``` var promises = [], defs = []; for(var i=0 ; i < 10 ; i++){ defs.push($.Deferred()); promises.push(defs[i].promise()); } var res = $.when.apply($, promises); res.fail(function(){console.log('failed')}); res.done(function(){console.log('done')}); res.always(function(){console.log('always')}); res.then(function(){console.log('then, done')}, function(){console.log('then, failed')}); var j = 0; var t = setInterval(function(){ if(j < 10){ if(j < 5) { console.log('resolve'); defs[j++].resolve(); } else { console.log('reject'); defs[j++].reject(); } } else { clearInterval(t); } }, 200); ``` Check this jsfiddle. Maybe it's the normal behavior. But, in this case, how can I catch the end of my chain even if some of them have failed?

Original source