2012-11-21 6 views
10

Ich verwende $.when, um einige Deferred-Objekte zu verketten, und wenn einer von ihnen fehlschlägt, wird die -Methode direkt nach dem Fehler aufgerufen, auch wenn ich noch einen Deferrer habe in einem "ausstehenden" Zustand.jquery deferred - "immer" beim ersten Reject aufgerufen

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); 

Überprüfen Sie this jsfiddle.

Vielleicht ist es das normale Verhalten. Aber wie kann ich in diesem Fall das Ende meiner Kette erreichen, selbst wenn einige von ihnen versagt haben?

Antwort

11

Es ist von Entwurf: Die Methode löst seinen Master Deferred, sobald alle Deferreds auflösen, oder den Master Deferred zurückweisen, sobald ein der Deferreds abgelehnt wird. [...] Beachten Sie, dass einige der Deferreds an diesem Punkt immer noch ungelöst sein können.

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

Sie können Verweise auf alle deferreds speichern und sie separat verfolgen.

Etwas wie folgt aus:

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/

+0

danke @ yury-tarabanko! Ich mag die Idee, jQuery zu erweitern und eine wiederverwendbare Methode hinzuzufügen, um alle Deferrer-Ends zu betrachten, selbst wenn sie fehlgeschlagen sind. Basierend auf Ihrer Idee und auf "wenn" jQuery Quelle, ich habe die "whenAll" wieder, überprüfen Sie die Quelle, wenn Sie Zeit haben http://jsfiddle.net/cSy2K/5/;) – zazabe

1

Ja, es ist ein normales Verhalten. Wenn einer fehlschlägt, scheitert auch die Sache, die auf allem beruht. Siehe auch die jQuery docs.

So, du hast entweder manuell zu verfolgen, oder Sie füttern nur Promises in when aufgelöst:

promises.push(defs[i].promise().then(function(x) { 
     return {result:x,resolved:true}; 
    }, function(x) { 
     return (new $.Deferred).resolve({result:x,resolved:false}); 
    }) 
); 

Damit Ihr res die done Rückruf nur nennen, wenn alle Versprechungen verarbeitet werden, und es wird Holen Sie sich ein Array von Objekten, die Status und Ergebnis von ihnen anzeigen.