2013-03-09 3 views
2

Avec jQuery.when(), si une requête échoue, ils échouent tous.

$.when(deferred1, deferred2).then(function() { 
    // Called only after both deferred are resolved 
}, function() { 
    // Called immediately after one of the deferreds is rejected 
}); 

Comment pouvez-vous attendre que tout exécute même des échecs? J'ai essayé d'utiliser .always() au lieu de .then() mais le rappel est également appelé juste après le premier échec.

Une solution (moche) serait d'avoir des drapeaux à contrôler lorsque les deux opérations sont terminées et d'utiliser le .always() sur chacun d'eux (sans $.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(); 
}); 

Y a-t-il une meilleure façon de procéder?

+0

J'ai trouvé d'autres solutions intéressantes dans cette question (http://stackoverflow.com/questions/12152595/jquery-deferreds-waiting-for-an-array-of-ajax-requests -to-complete-even-failur) et (http://stackoverflow.com/questions/5824615/jquery-when-callback-for-when-all-deferreds-are-no-long-unresolved-either-r) – Jonatan

Répondre

1

Jonatan,

J'aime votre solution et offre quelques améliorations:

  • phrase comme méthode utilitaire jQuery, comme $.when()
  • permettent promesses individuelles ou un réseau de promesses pour être transmis dans
  • détermination immédiatement si aucun argument ou un tableau vide est passé dans
  • être tolérant des non-promesses/non-différés
  • permettre le progrès de la chaîne à signaler lorsque chaque promesse est résolue ou rejetée.

Voici le code:

à appeler chaque fois qu'une promesse chain est reolved/rejeté, quel que soit l'ordre reolution/rejet
(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); 

Cette approche permettrait à tout progressCallbacks (ajouté à la promesse recalibrée). En transmettant le nombre de promesses chain en attente aux progressCallbacks, vous pouvez, par exemple, fournir une indication de compte à rebours ou répondre à des jalons de compte à rebours intermédiaires.

semble fonctionner - DEMO

2

Une autre solution (pas si laide) serait d'enchaîner les rappels différés .always().

deferred1.always(function() { 
    deferred2.always(function() { 
     // Execute after both deferred are either resolved or rejected 
    }); 
}); 

j'ai écrit une petite fonction pour gérer ceci:

function whenAlways() { 
    var chain = $.extend([], arguments); 
    return new $.Deferred(function(deferred) { 
     var callback = function() { 
      if (chain.length == 0) { 
       deferred.resolve(); 
       return; 
      } 
      var object = chain.shift(); 
      $.when(object).always(callback); 
     }; 
     callback(); 
    }).promise(); 
} 

Utilisation:

whenAlways(deferred1, deferred2) 
    .done(function() { 
     // Execute after both deferred are either resolved or rejected 
    }); 
Questions connexes