在承诺中,当时和最后有什么区别?

Jas*_*n C 12 javascript node.js promise bluebird

我看到Bluebird的文档,finally但我仍然不太了解与之相比的差异then.

要清楚:我确切地知道为什么then在a之后调用catch.我希望在捕获之后调用它.这是意图.我的问题是:如果我希望代码总是被执行而不管承诺状态,那么thenvs 之间的区别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);
Run Code Online (Sandbox Code Playgroud)

这测试了四种情况:

  1. .then(...).catch(...).then(...) 有了解决的承诺.
  2. .then(...).catch(...).then(...) 被拒绝的承诺.
  3. .then(...).catch(...).finally(...) 有了解决的承诺.
  4. .then(...).catch(...).finally(...) 被拒绝的承诺.

我看到的结果是情况1 + 2的行为与3 + 4相同:最后一位(thenfinally取决于测试)执行无论发生在它之前发生了什么,如预期的那样.该计划的输出是:

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
Run Code Online (Sandbox Code Playgroud)

现在,我问的原因是因为我看到了对我提出的另一个问题评论:

不确定你的承诺是否支持它,但你应该改变最后一个.then,.finally以便busy始终清除.

从我非常有限的知识then和上面的测试来看,似乎then已经足够了.但在那次评论之后,我正在质疑自己以及使用then执行"最终"代码的安全性.

所以我的问题是:then和之间有什么区别finally?他们看起来行为相同,但什么时候需要使用finally而不是then

Tho*_*mas 14

第一个区别:有时你不想在它们出现的地方捕获错误,但在使用这个函数的代码中,所以你不会捕获它们.在这种情况下,你不能替代then()finally().

有时你必须清理一些事情是否有错误(归零引用,清除超时......这样的东西).这就是你使用的地方finally().

第二个区别:你传递给的函数也catch()可能抛出,然后你会有一个被拒绝的Promise,并且then()不会调用以下内容.

(所以最后一个catch仍然会在错误上执行,不知道那个)

是的,这就是重点finally().它将在任何情况下执行而不更改已解析的值.

您可能想要阅读/谷歌一点try {} finally {},没有捕获.


Mat*_*att 7

.then并且.finally不一样。

.then是主要的承诺原语。这是Promises/A+ 规范中彻底定义的内容,所有 Promise 库都将实现它。

Bluebird.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
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)

这些方法在您的测试用例中看起来相似,因为测试会捕获所有错误,并且您仅使用 Promise 进行流控制,而不依赖于沿着 Promise 链解决/拒绝的值。

  • 顺便说一句,如果其他人正在阅读这篇文章,现在我已经掌握了这些概念,我发现了其他一些东西,而 `.tap()` 就是其中之一:`tap` 有点像 `then` 和`finally`:像 `then` 一样,它不会在拒绝时调用,但像 `finally` 一样,它不会改变结果,因此之前的结果会“跳过”它。整洁的。 (3认同)

Jas*_*n C 5

好吧,经过 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"));
}
Run Code Online (Sandbox Code Playgroud)

在这些中,承诺被拒绝,但从中抛出错误 catch.

在这两种情况下,promise 最终都被拒绝了,但对于仍然执行的finally情况finallythen则不是。

所以这就是区别。它们几乎相同,唯一的例外是当catch处理程序抛出错误时,finally执行和then不执行。

这意味着我引用的评论也有优点:如果在我的错误处理程序中发生另一个错误,athen不能保证清理,但 afinally会。这就是我失踪的情况。

  • 此外`.finally` 不会影响promise 的解析值,而`.then` 会。 (2认同)