2012-11-21 11 views
10

Używam $.when do połączenia niektórych obiektów odroczonych, a jeśli jeden z nich się nie powiedzie, metoda always zostanie wywołana bezpośrednio po awarii, nawet jeśli nadal mam trochę odroczenia w stanie "oczekującym".jquery odroczone - "zawsze" wywoływane przy pierwszym odrzuceniu

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

Sprawdź this jsfiddle.

Może to normalne zachowanie. Ale w tym przypadku, jak mogę złapać koniec mojego łańcucha, nawet jeśli niektóre z nich zawiodły?

Odpowiedz

11

Jest to zgodne z projektem: metoda rozwiąże jego mistrz odroczony jak najszybciej wszystkich determinacji Deferreds lub odrzucić mistrza odroczony jak najszybciej jeden z Deferreds zostaje odrzucony. [...] Pamiętaj, że niektóre z odroczonych wciąż mogą być nierozwiązane w tym momencie.

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

można zapisywać odwołania do wszystkich deferreds i zapisuje je oddzielnie.

coś takiego:

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

dzięki @ yury-tarabanko! Podoba mi się pomysł rozszerzenia jQuery i dodania metody wielokrotnego użytku, aby spojrzeć na koniec odrocza, nawet jeśli się nie powiodło. Opierając się na twoim pomyśle i na "kiedy" źródło jQuery, ponownie zrobiłem "whenAll", sprawdź źródło, jeśli masz czas http://jsfiddle.net/cSy2K/5/;) – zazabe

1

Tak, to jest normalne zachowanie. Jeśli się nie powiedzie, to i to, co zależy od wszystkich, również się nie powiedzie. Zobacz także jQuery docs.

Więc albo trzeba śledzić je ręcznie lub karmisz tylko rozwiązane Promises w when:

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

Dzięki temu Twój res zadzwoni tylko done oddzwanianie, gdy wszystkie obietnice są przetwarzane, i będzie uzyskać tablicę obiektów wskazującą status i wynik ich działania.

Powiązane problemy