J'ai du mal à comprendre la différence entre mettre .catch
AVANT et APRÈS alors dans une promesse imbriquée.
Alternative 1:
test1Async(10).then((res) => {
return test2Async(22)
.then((res) => {
return test3Async(100);
}).catch((err) => {
throw "ERROR AFTER THEN";
});
}).then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
Alternative 2:
test1Async(10).then((res) => {
return test2Async(22)
.catch((err) => {
throw "ERROR BEFORE THEN";
})
.then((res) => {
return test3Async(100);
});
}).then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
Le comportement de chaque fonction est le suivant, test1 échoue si nombre est <0
test2 échoue si nombre est > 10
et test3 échoue si nombre ne l'est pas 100
. Dans ce cas, test2 échoue seulement.
J'ai essayé d'exécuter et de faire échouer test2Async, AVANT et APRÈS, puis se comporte de la même manière et cela n'exécute pas le test3Async. Quelqu'un peut-il m'expliquer la principale différence pour placer les prises à différents endroits?
Dans chaque fonction je console.log('Running test X')
pour vérifier si elle est exécutée.
Cette question se pose à cause du fil de discussion précédent que j'ai posté Comment transformer un rappel imbriqué en promesse? . Je pense que c'est un problème différent et qu'il vaut la peine de publier un autre sujet.
Réponses:
Donc, en gros, vous demandez quelle est la différence entre ces deux (où
p
est une promesse créée à partir d'un code précédent):et
Il existe des différences lorsque p résout ou rejette, mais que ces différences comptent ou non dépend de ce que fait le code à l'intérieur des gestionnaires
.then()
ou.catch()
.Que se passe-t-il lorsque
p
résout:Dans le premier schéma, lors de la
p
résolution, le.then()
gestionnaire est appelé. Si ce.then()
gestionnaire renvoie une valeur ou une autre promesse qui finit par se résoudre, alors le.catch()
gestionnaire est ignoré. Mais, si le.then()
gestionnaire lève ou retourne une promesse qui finalement rejette, alors le.catch()
gestionnaire exécutera à la fois un rejet dans la promesse d'originep
, mais aussi une erreur qui se produit dans le.then()
gestionnaire.Dans le second schéma, lors de la
p
résolution, le.then()
gestionnaire est appelé. Si ce.then()
gestionnaire lève ou retourne une promesse qui finit par rejeter, alors le.catch()
gestionnaire ne peut pas l'attraper car c'est avant lui dans la chaîne.Donc, c'est la différence n ° 1. Si le
.catch()
gestionnaire est AFTER, il peut également intercepter des erreurs à l'intérieur du.then()
gestionnaire.Que se passe-t-il en cas de
p
rejet:Maintenant, dans le premier schéma, si la promesse est
p
rejetée, alors le.then()
gestionnaire est ignoré et le.catch()
gestionnaire sera appelé comme prévu. Ce que vous faites dans le.catch()
gestionnaire détermine ce qui est renvoyé comme résultat final. Si vous retournez simplement une valeur du.catch()
gestionnaire ou si vous retournez une promesse qui se résout finalement, la chaîne de promesse passe à l'état résolu car vous avez "géré" l'erreur et l'avez renvoyée normalement. Si vous lancez ou renvoyez une promesse rejetée dans le.catch()
gestionnaire, la promesse retournée reste rejetée.Dans le second schéma, si la promesse est
p
rejetée, le.catch()
gestionnaire est appelé. Si vous retournez une valeur normale ou une promesse qui se résout finalement à partir du.catch()
gestionnaire ("gérant" ainsi l'erreur), alors la chaîne de promesse passe à l'état résolu et le.then()
gestionnaire après le.catch()
sera appelé.Voilà donc la différence n ° 2. Si le
.catch()
gestionnaire est BEFORE, il peut gérer l'erreur et autoriser le.then()
gestionnaire à être appelé.Quand utiliser lequel:
Utilisez le premier schéma si vous ne voulez qu'un seul
.catch()
gestionnaire qui puisse intercepter les erreurs dans la promesse d'originep
ou dans le.then()
gestionnaire et un rejet dep
devrait ignorer le.then()
gestionnaire.Utilisez le deuxième schéma si vous voulez être en mesure de détecter les erreurs dans la promesse d'origine
p
et peut-être (selon les conditions), permettre à la chaîne de promesse de continuer comme résolue, exécutant ainsi le.then()
gestionnaire.L'autre option
Il existe une autre option pour utiliser les deux rappels auxquels vous pouvez passer
.then()
comme dans:Cela garantit qu'un seul
fn1
oufn2
sera appelé. Sip
résout, alorsfn1
sera appelé. Sip
rejette, alorsfn2
sera appelé. Aucun changement de résultatfn1
ne peut jamais fairefn2
être appelé ou vice versa. Donc, si vous voulez être absolument sûr qu'un seul de vos deux gestionnaires est appelé indépendamment de ce qui se passe dans les gestionnaires eux-mêmes, vous pouvez utiliserp.then(fn1, fn2)
.la source
.then()
et.catch()
, auquel vous répondez. De plus, vous donnez quelques astuces pour savoir quand utiliser quel ordre, où je pense qu'il est approprié de mentionner une troisième option, à savoir passer à la fois le gestionnaire de succès et d'erreur à .then () . Dans ce cas, au plus un gestionnaire sera appelé.Promise.reject(new Error("F")).then(x => x).catch(e => {console.log(e); return [1]}).then(console.log)
etPromise.resolve([2]).then(x => x).catch(e => [1]).then(console.log)
.then(this.setState({isModalOpen: false}))
. Vous ne passez pas une référence de fonction à.then()
afin que le code dans les parenthèses soit exécuté immédiatement (avant la résolution de la promesse). Ça devrait être.then(() => this.setState({isModalOpen: false}))
.La réponse de jfriend00 est excellente, mais j'ai pensé que ce serait une bonne idée d'ajouter le code synchrone analogue.
est similaire au synchrone:
Si
iMightThrow()
ne lance pas,then()
sera appelé. S'il lance (ou s'ilthen()
lance lui - même), alorshandleCatch()
sera appelé. Remarquez que lecatch
bloc n'a aucun contrôle sur l'then
appel ou non .D'autre part,
est similaire au synchrone:
Dans ce cas, si
iMightThrow()
ne lance pas, alorsthen()
s'exécutera. S'il le lance, il appartiendra alorshandleCatch()
de décider s'ilthen()
est appelé, car s'il esthandleCatch()
relancé, ilthen()
ne sera pas appelé, car l'exception sera immédiatement renvoyée à l'appelant. SihandleCatch()
peut gérer le problème avec élégance, alorsthen()
sera appelé.la source
then()
dans unfinally{...}
then()
enfinally{...}
, ne serait - il être appelé à tort , même sihandleCatch()
jette? Gardez à l'esprit que mon objectif était de montrer un code synchrone analogue, et non de suggérer différentes façons de gérer les exceptions