Rupture de la promesse et de la chaîne d'appeler une fonction sur la base de l'étape dans la chaîne où il est cassé (rejeté)
Mise à jour:
Pour aider les futurs spectateurs de ce post, j'ai créé cette démo de pluma de réponse.
Question:
Mon objectif semble assez simple.
step(1)
.then(function() {
return step(2);
}, function() {
stepError(1);
return $q.reject();
})
.then(function() {
}, function() {
stepError(2);
});
function step(n) {
var deferred = $q.defer();
//fail on step 1
(n === 1) ? deferred.reject() : deferred.resolve();
return deferred.promise;
}
function stepError(n) {
console.log(n);
}
Le problème ici est que si j'échoue à l'étape 1, à la fois stepError(1)
ET stepError(2)
sont licenciés. Si je n'ai pas return $q.reject
puis stepError(2)
de ne pas être congédié, mais step(2)
va, que je comprends. J'ai accompli tout sauf ce que je suis en train de faire.
Comment puis-je écrire des promesses alors que je peux appeler une fonction sur le rejet sans appel de toutes les fonctions dans l'erreur de la chaîne? Ou est-il une autre façon d'accomplir cette?
Voici une démo en live de sorte que vous avez quelque chose à travailler avec.
Mise à jour:
Je genre de l'avez résolu. Ici, je suis la capture de l'erreur à la fin de la chaîne et de transmettre les données reject(data)
de sorte que je saurai ce problème à gérer dans la fonction d'erreur. En fait, cela ne répond pas à mes besoins, car je ne veux pas dépendre des données. Il serait boiteux, mais dans mon cas, il serait plus propre de passer à une erreur de rappel à la fonction plutôt que de dépendre sur les données renvoyées à déterminer quoi faire.
Démonstration en direct ici (cliquez).
step(1)
.then(function() {
return step(2);
})
.then(function() {
return step(3);
})
.then(false,
function(x) {
stepError(x);
}
);
function step(n) {
console.log('Step '+n);
var deferred = $q.defer();
(n === 1) ? deferred.reject(n) : deferred.resolve(n);
return deferred.promise;
}
function stepError(n) {
console.log('Error '+n);
}
- Il y a un asynchrone en javascript lib qui pourrait Aider si cela devient plus compliqué
Promise.prototype.catch()
exemples sur MDN voir la solution pour exactement les mêmes questions.
Vous devez vous connecter pour publier un commentaire.
La raison que votre code ne fonctionne pas comme prévu, c'est qu'il est en train de faire quelque chose de différent de ce que vous pensez que cela fonctionne.
Disons que vous avez quelque chose comme ce qui suit:
Afin de mieux comprendre ce qui se passe, faisons semblant de croire que c'est du code synchrone avec
try
/catch
blocs:La
onRejected
gestionnaire (le deuxième argument dethen
) est essentiellement un mécanisme de correction des erreurs (comme uncatch
bloc). Si une erreur est renvoyée danshandleErrorOne
, il sera pris par le prochain bloc catch (catch(e2)
), et ainsi de suite.Ce n'est évidemment pas ce que vous souhaitiez.
Disons que nous voulons que l'ensemble de la résolution de la chaîne échoué, peu importe ce qui va mal:
Remarque: Nous ne pouvons laisser la
handleErrorOne
où il est, car il va seulement être invoquée sistepOne
rejette (c'est la première fonction de la chaîne, de sorte que nous savons que si la chaîne est rejetée à ce stade, il ne peut être en raison de cette fonction de la promesse).Le changement important est que les gestionnaires d'erreur pour les autres fonctions ne font pas partie de la principale promesse de la chaîne. Au lieu de cela, chaque étape a son propre "sous-chaîne" avec un
onRejected
qui n'est appelée que si l'étape a été rejetée (mais ne peut pas être atteint par la chaîne principale directement).La raison pour laquelle cela fonctionne est que les deux
onFulfilled
etonRejected
sont des arguments facultatifs à lathen
méthode. Si une promesse est remplie (c'est à dire résolu) et la prochainethen
dans la chaîne n'ont pas deonFulfilled
gestionnaire, la chaîne continuera jusqu'à ce qu'il y en a un avec un gestionnaire.Cela signifie que les deux lignes suivantes sont équivalentes:
Mais la ligne suivante est pas équivalent aux deux ci-dessus:
Angulaire de la promesse de la bibliothèque
$q
est basé sur kriskowal deQ
de la bibliothèque (qui est plus riche de l'API, mais il contient tout ce que vous pouvez trouver dans$q
). Q Les docs de l'API sur GitHub pourrait s'avérer utile. Q implémente l' Promesses/A+ caractéristiques, qui va dans le détail sur la façon dontthen
et la promesse de résolution de comportement fonctionne exactement.EDIT:
Aussi garder à l'esprit que si vous voulez sortir de la chaîne dans votre gestionnaire d'erreur, il doit retourner le refus de la promesse ou de jeter une Erreur (qui sera pris et enveloppé dans le refus de la promesse automatiquement). Si vous ne rentrez pas une promesse,
then
encapsule la valeur de retour dans la résolution de la promesse de vous.Cela signifie que si vous ne retourne rien, vous êtes effectivement en retour d'un résolus promesse pour la valeur
undefined
.if you don't return anything, you are effectively returning a resolved promise for the value undefined.
Merci @plumastepOne().then(stepTwo, handleErrorOne)
` stepOne().ensuite, (null, handleErrorOne).ensuite(stepTwo) " Sont ces trully équivalent? Je pense que dans le cas de rejet dansstepOne
la deuxième ligne de code s'exécutestepTwo
mais le premier ne s'exécuterahandleErrorOne
et de s'arrêter. Ou ai-je raté quelque chose?Peu en retard à la fête, mais cette solution simple a fonctionné pour moi:
Cela vous permet de pause de la chaîne.
.then(user => { if (user) return Promise.reject('The email address already exists.') })
.then(user => { if (user) throw 'The email address already exists.' })
Ce que vous avez besoin est une répétition de
.then()
de la chaîne avec un cas particulier pour commencer et un cas particulier à la fin.Le truc est d'obtenir le numéro de l'étape de la cas d'échec à l'ondulation grâce à un final gestionnaire d'erreur.
step(1)
sans condition..then()
avec les rappels suivants:.then()
sans succès, de gestionnaire et de gestionnaire d'erreur.Vous pouvez écrire toute chose dans la main, mais il est plus facile de démontrer le modèle nommés, généralisées de fonctions :
voir démo
Noter comment, dans
step()
, le différé est rejetée ou résolus avecn
, rendant ainsi que la valeur à la disposition des rappels dans la prochaine.then()
dans la chaîne. Une foisstepError
est appelée, l'erreur est relancés à plusieurs reprises jusqu'à ce qu'il soit traité parfinalError
.Lors du rejet que vous devriez passer un rejet d'erreur, puis les envelopper étape gestionnaires d'erreur dans une fonction qui vérifie si le rejet devraient être traitées ou "relancés" jusqu'à la fin de la chaîne :
Ce que vous souhaitez voir sur la console :
Voici du code de travail
https://jsfiddle.net/8hzg5s7m/3/
Si vous avez un traitement spécifique pour chaque étape, votre enveloppe pourrait être quelque chose comme:
alors votre chaîne
Si je comprends bien, vous voulez seulement l'erreur en cas d'échec à l'étape de montrer, non?
Qui devrait être aussi simple que de changer le cas d'échec de la première promesse:
En retournant
$q.reject()
dans la première étape du cas d'échec, vous êtes en rejetant cette promesse, ce qui provoque la errorCallback d'être appelé dans le 2èmethen(...)
.step(2)
. Maintenant, j'ai juste essayé de nouveau, il ne se passe rien. Je suis tellement confus.return step(2);
ne doit jamais être appelée lorsquestep(1)
résout avec succès.return $q.reject()
, la chaîne va continuer. Dans ce casreturn response
a tout fait foiré. Voir ceci: jsbin.com/EpaZIsIp/6/edithttp://jsbin.com/EpaZIsIp/20/edit
Ou automatisé pour un certain nombre d'étapes:
http://jsbin.com/EpaZIsIp/21/edit
deferred.reject(n)
alors je suis d'avertissement qui promettent rejeté avec une nonError objetSi vous voulez résoudre ce problème en utilisant async/await:
Joindre les gestionnaires d'erreur en tant que distincte de la chaîne d'éléments directement à l'exécution de la procédure:
ou à l'aide de
catch()
:Note: Ceci est fondamentalement le même modèle que pluma l'indique dans sa réponse mais à l'aide de l'OP de nommage du.
Trouvé
Promesse.le prototype.catch()
exemples sur MDN ci-dessous très utile.(La accepté de répondre mentionne
then(null, onErrorHandler)
qui est fondamentalement la même quecatch(onErrorHandler)
.)La meilleure solution est de revoir votre promesse de la chaîne d'utiliser ES6 attendent du. Ensuite, vous pouvez juste retour de la fonction à ignorer le reste du comportement.
J'ai été frapper ma tête contre ce modèle depuis plus d'un an et à l'aide de attendent du est le ciel.
Essayer ro utiliser comme libs:
https://www.npmjs.com/package/promise-chain-break
Utiliser un SequentialPromise Module
Intention
Fournir un module dont la responsabilité est d'exécuter les demandes de manière séquentielle, tandis que le suivi de l'index actuel de chaque opération dans un ordinal manière. Définir le fonctionnement dans un Modèle de Commande pour plus de flexibilité.
Participants
execute
méthode de la chaîne d' & faire le suivi de chaque opération. SequentialPromise retourne une Promesse-la Chaîne de toutes les opérations effectuées.execute
méthode en passant dans un ordinal liste des options disponibles pour chaque opération.Conséquences
Utilisation SequentialPromise quand ordinale comportement de la Promesse de résolution est nécessaire. SequentialPromise permettra de suivre l'index pour lesquels une Promesse a été rejetée.
Mise en œuvre
Gist
SequentialPromise