我看到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
现在,我问的原因是因为我看到了comment on this other question I asked:
不确定您的承诺是否支持,但您应将最后
.then
更改为.finally
,以便busy
始终被清除。
根据我对then
的非常有限的了解以及上面的测试,似乎then
就足够了。但在那次评论之后,我正在质疑自己以及使用then
执行“最终”代码的安全性。
所以我的问题是:then
和finally
之间有什么区别?他们看起来就像他们的行为一样,但我什么时候需要使用finally
代替then
?
答案 0 :(得分:8)
第一个区别:有时你不想在它们出现的地方发现错误,但是在使用这个功能的代码中,所以你不会抓住它们。在这种情况下,您无法替换then()
和finally()
。
有时你必须清理一些事情是否有错误(归零引用,清除超时......这样的东西)。您使用finally()
的地方。
第二个区别:你传递给catch()
的函数也可能抛出,然后你会被拒绝的Promise,并且不会调用以下的then()
。
(所以最后一个捕获仍然会在错误上执行,并不知道)
是的,这是finally()
的重点。它将在任何情况下执行,而不会更改已解决的值。
你可能想要阅读/谷歌一点try {} finally {}
,没有捕获。
答案 1 :(得分:4)
.then
和.finally
不一样。
.then
是主要的promise原语。它是Promises/A+ spec中完全定义的内容,所有承诺库都会实现它。
无论承诺的命运如何,都会召唤一只蓝鸟.finally
处理程序"因此,未处理的异常仍会触发.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
这些方法在测试用例中看起来类似,因为测试会捕获所有错误,并且您只使用promises进行流控制,而不依赖于在promise链中解析/拒绝的值。
答案 2 :(得分:1)
好吧,经过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
会引发错误。
最终在两种情况下都会拒绝承诺,但对于finally
案例finally
仍然执行,then
不会。
他们几乎相同,但唯一的例外是,当 catch
处理程序发出错误时,finally
会执行,{ {1}}没有。
这意味着我引用的评论也有其优点:如果在我的错误处理程序中发生了另一个错误,then
将无法保证清理,但then
会发生错误。这就是我失踪的情况。