2017-03-21 4 views
0

J'ai une fonction de séquençage qui a essentiellement deux étapes REST - étapes 1 et 2. Je le gère de la façon suivante - en appelant step1 et en ayant un fail et un puis handlers pour cela et puis suivi par le second appel - step2 avec son propre échec puis gestionnaire.Jquery Deferreds - le second échec est appelé de façon inattendue

self.step1() 
    .fail(self.onStep1Fail.bind(self)) 
    .then(self.onStep1Done.bind(self)) 
    .then(self.step2.bind(self)) 
    .fail(self.onStep2Fail.bind(self)) 
    .then(self.onStepDone.bind(self)); 

Ma lecture de cette séquence est que l'étape 1 est appelé, et si elle échoue, la méthode de l'échec step1 sera appelée. Si step1 réussit, step1Done et step2 seront appelés en séquence, puis l'étape 2 déterminera si step2Fail ou Step2Done seront appelés.

Mais pour une raison quelconque, Step1Fail et Step2Fail sont appelés lorsque l'étape 1 échoue - ce qui est inattendu. Quelqu'un sait-il pourquoi? Aussi, comment puis-je changer cela pour réaliser ce que j'essaie - pour que step2Fail soit appelé seulement après que l'étape 2 a été réellement effectuée.

J'atteint un peu cela en utilisant l'approche suivante:

var handled = false; 

    function onCatch(handler) { 
     if (!handled) { 
      handled = true; 
      handler.call(self, Array.prototype.slice.call(window.Array.apply(null, arguments), 1)); 
     } 
     return $.Deferred().reject().promise(); 
    } 

    self.step1() 
     .catch(onCatch.bind(self, self.step1Fail)) 
     .then(self.step1Done.bind(self)) 
     .then(self.step2.bind(self)) 
     .catch(onCatch.bind(self, self.step2Fail)) 
     .then(self.step2Done.bind(self)); 

Mais je suis à la recherche pour voir s'il y a une à cette méthode simple. Il suffit d'attacher un gestionnaire d'échec, sans aucun chaînage de rappel, il renvoie l'entrée différée.

Répondre

0

fail

Lorsque step1() échoue, toute la chaîne le fait, c'est-à-dire que toute promesse dans la chaîne est rejetée. Et les gestionnaires d'échec de chaque promesse seront déclenchés, dans votre cas à la fois onStep1Fail et onStep2Fail.

Si vous voulez que les gestionnaires onStep2… à invoquer que lorsque step2 est exécuté, ne les mettez pas sur toute la chaîne:

self.step1() 
.fail(self.onStep1Fail.bind(self)) 
.then(self.onStep1Done.bind(self)) 
.then(function(step1doneResult) { 
    return self.step2(step1doneResult) 
    .fail(self.onStep2Fail.bind(self)) 
    .then(self.onStepDone.bind(self)); 
}); 

Je recommande de ne pas utiliser la méthode fail du tout pour son manque de chaînage. Au lieu de cela, utilisez le deuxième paramètre de then:

self.step1() 
.then(self.onStep1Done.bind(self), self.onStep1Fail.bind(self)) 
.then(function(step1handlerResult) { 
    return self.step2(step1handlerResult) 
    .then(self.onStepDone.bind(self), self.onStep2Fail.bind(self)); 
}); 
+0

Il n'est pas obtenir illisible, le pouvoir des promesses est qu'ils enchaînent de façon linéaire au lieu de nidification comme callbacks. Bien sûr, si vous voulez faire une distinction succès/échec à chaque étape, cela vous permet d'imbriquer comme des branches 'if'/'else' - et d'imbriquer [blocs] (https://en.wikipedia.org/wiki/Block_ (programmation)) est totalement naturel dans la programmation structurée. – Bergi

+0

Merci! Donc c'est prévu alors! J'essayais d'éviter l'imbrication autant que possible, car cela rend le code illisible des heures supplémentaires, surtout si d'autres étapes sont en cours. En outre, je préfère généralement attraper pour échouer. –

+0

Oui, ['catch'] (http://api.jquery.com/deferred.catch/) (disponible depuis jQuery 3) est correct, bien qu'il soit fondamentalement différent de' fail ' – Bergi