then 和 finally 在承诺中有什么区别?
What is the difference between then and finally in a promise?
我看到了 Bluebird 的 finally
文档,但我仍然不太明白与 then
的区别。
明确一点:我确切地知道为什么 then
在 catch
之后被调用。我希望 它在捕获后被调用。这就是意图。我的问题是:如果我 想要 代码始终执行而不管承诺状态如何,那么 then
与 finally
之间有什么区别?
我构建了这个测试:
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);
这测试了四种情况:
.then(...).catch(...).then(...)
一个坚定的承诺。
.then(...).catch(...).then(...)
承诺被拒绝。
.then(...).catch(...).finally(...)
兑现承诺。
.then(...).catch(...).finally(...)
被拒绝的承诺。
我看到的结果是情况 1+2 的行为与 3+4 相同:最后一位(then
或 finally
取决于测试)按预期执行,无论之前发生什么.该程序的输出是:
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
现在,我问的原因是因为我看到 :
Not sure if your promises support it, but you should change the last .then
to .finally
so that the busy
always gets cleared.
根据我对 then
非常有限的了解,以及上面的测试,似乎 then
就足够了。但在那条评论之后,我质疑自己以及使用 then
执行 "finally" 代码的安全性。
所以我的问题是:then
和 finally
有什么区别?他们 看起来 就像他们的行为一样,但我什么时候需要使用 finally
而不是 then
?
好吧,经过一番交谈和 KevinB 的大量帮助,我至少找出了一个不同之处。考虑以下两个新测试:
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"));
}
在这些中,承诺被拒绝,但从 catch
中抛出错误。
在这两种情况下,promise 最终都被拒绝了,但是对于 finally
的情况,finally
仍然被执行,then
没有。
所以这就是的区别。它们 几乎 相同,唯一的例外是当 catch
处理程序抛出错误时,finally
执行,而 then
不执行。
这意味着我引用的评论也有其优点:如果在我的错误处理程序中发生另一个错误,then
不能保证清除,但 finally
可以。这就是我想念的情况。
第一个区别:有时您不想在错误出现的地方捕获错误,而是在使用此函数的代码中,因此您不会捕获它们。在那种情况下,您不能替换 then()
和 finally()
。
有时无论是否有错误,您都必须清理一些东西(清空引用、清除超时...诸如此类)。那就是你使用 finally()
的地方。
第二个区别:你传递给 catch()
的函数也可能抛出,然后你将有一个被拒绝的 Promise 并且下面的 then()
将不会被调用。
(so a finally before a catch will still execute on an error, didn't know that)
是的,这就是 finally()
的重点。任何情况下都会执行,解析值不变。
您可能想 read/google 稍微了解一下 try {} finally {}
,而不用担心。
.then
和.finally
不一样。
.then
是主要的 promise 原语。它是 Promises/A+ spec 中彻底定义的内容,所有 promise 库都将实现它。
Bluebird .finally
处理程序将 "be called regardless of the promise's fate"。所以未处理的异常仍然会触发 .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
不会更改承诺的解析值,也不会收到承诺链的结果。
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
这些方法在您的测试用例中看起来很相似,因为测试会捕获所有错误,并且您仅使用承诺进行流量控制,而不依赖承诺链中 resolve/rejected 的值。
我看到了 Bluebird 的 finally
文档,但我仍然不太明白与 then
的区别。
明确一点:我确切地知道为什么 then
在 catch
之后被调用。我希望 它在捕获后被调用。这就是意图。我的问题是:如果我 想要 代码始终执行而不管承诺状态如何,那么 then
与 finally
之间有什么区别?
我构建了这个测试:
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);
这测试了四种情况:
.then(...).catch(...).then(...)
一个坚定的承诺。.then(...).catch(...).then(...)
承诺被拒绝。.then(...).catch(...).finally(...)
兑现承诺。.then(...).catch(...).finally(...)
被拒绝的承诺。
我看到的结果是情况 1+2 的行为与 3+4 相同:最后一位(then
或 finally
取决于测试)按预期执行,无论之前发生什么.该程序的输出是:
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
现在,我问的原因是因为我看到
Not sure if your promises support it, but you should change the last
.then
to.finally
so that thebusy
always gets cleared.
根据我对 then
非常有限的了解,以及上面的测试,似乎 then
就足够了。但在那条评论之后,我质疑自己以及使用 then
执行 "finally" 代码的安全性。
所以我的问题是:then
和 finally
有什么区别?他们 看起来 就像他们的行为一样,但我什么时候需要使用 finally
而不是 then
?
好吧,经过一番交谈和 KevinB 的大量帮助,我至少找出了一个不同之处。考虑以下两个新测试:
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"));
}
在这些中,承诺被拒绝,但从 catch
中抛出错误。
在这两种情况下,promise 最终都被拒绝了,但是对于 finally
的情况,finally
仍然被执行,then
没有。
所以这就是的区别。它们 几乎 相同,唯一的例外是当 catch
处理程序抛出错误时,finally
执行,而 then
不执行。
这意味着我引用的评论也有其优点:如果在我的错误处理程序中发生另一个错误,then
不能保证清除,但 finally
可以。这就是我想念的情况。
第一个区别:有时您不想在错误出现的地方捕获错误,而是在使用此函数的代码中,因此您不会捕获它们。在那种情况下,您不能替换 then()
和 finally()
。
有时无论是否有错误,您都必须清理一些东西(清空引用、清除超时...诸如此类)。那就是你使用 finally()
的地方。
第二个区别:你传递给 catch()
的函数也可能抛出,然后你将有一个被拒绝的 Promise 并且下面的 then()
将不会被调用。
(so a finally before a catch will still execute on an error, didn't know that)
是的,这就是 finally()
的重点。任何情况下都会执行,解析值不变。
您可能想 read/google 稍微了解一下 try {} finally {}
,而不用担心。
.then
和.finally
不一样。
.then
是主要的 promise 原语。它是 Promises/A+ spec 中彻底定义的内容,所有 promise 库都将实现它。
Bluebird .finally
处理程序将 "be called regardless of the promise's fate"。所以未处理的异常仍然会触发 .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
不会更改承诺的解析值,也不会收到承诺链的结果。
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
这些方法在您的测试用例中看起来很相似,因为测试会捕获所有错误,并且您仅使用承诺进行流量控制,而不依赖承诺链中 resolve/rejected 的值。