Je vois la documentation pour le finally
de Bluebird, mais je ne comprends toujours pas très bien la différence entre then
.
Pour être clair: je sais exactement pourquoi then
est appelé après une catch
. I veux qu'il soit appelé après une prise. C'est l'intention. Ma question est la suivante: si je veux le code doit toujours être exécuté quel que soit l'état de la promesse, quelle est la différence entre then
et finally
pour cela?
J'ai construit ce test:
var Promise = require("bluebird");
function test1 () {
console.log("RESOLVE + THEN + CATCH + THEN");
return new Promise((resolve, reject) => resolve())
.then(() => console.log("then"))
.catch(err => console.log("error:", err.message))
.then(() => console.log("end"));
}
function test2 () {
console.log("REJECT + THEN + CATCH + THEN");
return new Promise((resolve, reject) => reject(new Error("rejected")))
.then(() => console.log("then"))
.catch(err => console.log("error:", err.message))
.then(() => console.log("end"));
}
function test3 () {
console.log("RESOLVE + THEN + CATCH + FINALLY");
return new Promise((resolve, reject) => resolve())
.then(() => console.log("then"))
.catch(err => console.log("error:", err.message))
.finally(() => console.log("end"));
}
function test4 () {
console.log("REJECT + THEN + CATCH + FINALLY");
return new Promise((resolve, reject) => reject(new Error("rejected")))
.then(() => console.log("then"))
.catch(err => console.log("error:", err.message))
.finally(() => console.log("end"));
}
// run tests "sequentially" so console output doesn't get blended
setTimeout(test1, 500);
setTimeout(test2, 1000);
setTimeout(test3, 1500);
setTimeout(test4, 2000);
Ceci teste quatre cas:
.then(...).catch(...).then(...)
avec une promesse résolue..then(...).catch(...).then(...)
avec une promesse refusée..then(...).catch(...).finally(...)
avec une promesse résolue..then(...).catch(...).finally(...)
avec une promesse refusée.Les résultats que je vois sont les cas 1 + 2 se comportent de manière identique à 3 + 4: le dernier bit (then
ou finally
en fonction du test) est exécuté quoi qu'il se passe avant, comme prévu. Le résultat de ce programme est:
RESOLVE + THEN + CATCH + THEN
then
end
REJECT + THEN + CATCH + THEN
error: rejected
end
RESOLVE + THEN + CATCH + FINALLY
then
end
REJECT + THEN + CATCH + FINALLY
error: rejected
end
Maintenant, la raison pour laquelle je pose la question est parce que j’ai vu un commenter cette autre question que j’ai posée }:
Vous n'êtes pas sûr que vos promesses le prennent en charge, mais vous devez remplacer le dernier
.then
par.finally
afin que la variablebusy
soit toujours effacée.
D'après ma connaissance très limitée de then
et les tests ci-dessus, il semble que then
soit suffisant. Mais après ce commentaire, je me pose des questions sur moi-même et sur la sécurité de l’utilisation de then
pour exécuter du code "enfin".
Ma question est donc la suivante: quelle est la différence entre then
et finally
? Ils look aiment bien se comporter de la même manière, mais quand aurais-je besoin d'utiliser finally
au lieu de then
?
Première différence: parfois, vous ne voulez pas intercepter les erreurs à l’endroit où elles se produisent, mais dans le code qui utilise cette fonction pour ne pas les intercepter. Dans ce cas, vous ne pouvez pas remplacer then()
et finally()
.
Parfois, vous devez nettoyer quelque chose, qu’il s’agisse d’une erreur ou non (annulation des références, suppression des délais impartis, etc.). C'est là que vous utilisez finally()
.
Deuxième différence: la fonction que vous transmettez à catch()
peut également être lancée. Dans ce cas, votre promesse serait rejetée et la then()
suivante ne serait pas appelée.
(donc, finalement, un catch exécutera toujours une erreur, je ne le savais pas)
Oui, c'est le point de finally()
. Il sera exécuté en toutes circonstances sans changer la valeur résolue.
Vous voudrez peut-être lire/google un peu sur try {} finally {}
, sans catch.
.then
et .finally
ne sont pas identiques.
.then
est la primitive de promesse principale. C'est ce qui est défini, à fond, dans Promises/A + spec et toutes les bibliothèques de promesses le mettront en œuvre.
Un Bluebird .finally
handler sera "appelé quel que soit le sort de la promesse". Donc, une exception non gérée déclenche toujours un .finally
.
new Promise((resolve, reject) => reject(false))
.finally(a => console.log('finally', a))
// finally undefined
// Unhandled rejection false
new Promise((resolve, reject) => reject(false))
.then(a => console.log('then', a))
// Unhandled rejection false
.finally
ne changera pas la valeur résolue de la promesse et ne recevra pas le résultat de la chaîne de promesse.
new Promise((resolve, reject) => reject(false))
.catch(e => {
console.log(e)
return 2
})
.finally(a => {
console.log('finally', a)
return 1
})
.then(res => console.log('res', res))
// finally undefined
// res 2
Les méthodes ont une apparence similaire dans vos scénarios de test car les tests détectent toutes les erreurs et vous utilisez uniquement des promesses pour le contrôle de flux, sans vous fier aux valeurs résolues/rejetées le long de la chaîne de promesses.
D'accord, après avoir discuté et beaucoup d'aide de KevinB, j'ai découvert au moins une différence. Considérez les deux nouveaux tests suivants:
function test5 () {
console.log("REJECT + THEN + CATCH/THROW + THEN");
return new Promise((resolve, reject) => reject(new Error("rejected")))
.then(() => console.log("then"))
.catch(function(err) { throw new Error("error in catch"); })
.then(() => console.log("end"));
}
function test6 () {
console.log("REJECT + THEN + CATCH/THROW + FINALLY");
return new Promise((resolve, reject) => reject(new Error("rejected")))
.then(() => console.log("then"))
.catch(function(err) { throw new Error("error in catch"); })
.finally(() => console.log("end"));
}
Dans ceux-ci, la promesse est rejetée, mais une erreur est générée par catch
.
La promesse finit par être rejetée dans les deux cas, mais pour le cas finally
le finally
est toujours exécuté, le then
ne l’est pas.
Donc c'est la différence. Ils sont presque les mêmes, à la seule exception que, lorsqu'une erreur est générée par lecatch
handler, finally
est exécuté et que then
ne le fait pas.
Cela signifie que le commentaire que j'ai cité a également un intérêt: si dans mon gestionnaire d'erreurs une autre erreur se produisait, une variable then
ne garantirait pas le nettoyage, mais une variable finally
le ferait. C'est le cas qui me manquait.