ES2018 中 finally() 和 then() 的区别

Difference between finally() and then() in ES2018

在 ES2018 之前,每当我必须执行任何清理逻辑时,我都会在承诺链的末尾嵌套一个额外的 then,否则我会在 thencatch 以上,例如

new Promise(
  (res, rej) => setTimeout(() => rej({}), 1000)
).then(
  res => console.log(res)
).catch(
  err => console.error(err)
).then(
  () => console.log('Finally')
)

但是现在在Promise原型上添加了finally,我看不出它与上面方法中的最后一个then有什么不同。以下将产生相同的输出。

new Promise(
  (res, rej) => setTimeout(() => rej({}), 1000)
).then(
  res => console.log(res)
).catch(
  err => console.error(err)
).finally(
  () => console.log('Finally')
)

finally 是否仅在本机 Promise API 中用于语义目的?

finally() 执行承诺是否履行或拒绝。也许 MDN doc 的示例会有所帮助。

编辑:MDN 文档给出了与 then():

的这些差异

The finally() method is very similar to calling .then(onFinally, onFinally) however there are couple of differences:

  • When creating a function inline, you can pass it once, instead of being forced to either declare it twice, or create a variable for it
  • A finally callback will not receive any argument, since there's no reliable means of determining if the promise was fulfilled or rejected. This use case is for precisely when you do not care about the rejection reason, or the fulfillment value, and so there's no need to provide it.
  • Unlike Promise.resolve(2).then(() => {}, () => {}) (which will be resolved with undefined), Promise.resolve(2).finally(() => {}) will be resolved with 2.
  • Similarly, unlike Promise.reject(3).then(() => {}, () => {}) (which will be fulfilled with undefined), Promise.reject(3).finally(() => {}) will be rejected with 3.

当 promise 被拒绝时,then 回调不会执行 - 即使对于 catch 调用返回的 promise 也会发生这种情况:当它的回调抛出或 returns被拒绝的承诺err => console.error(err) 可能 不会那样做,但你永远不知道。

同样,如果您只想处理来自原始承诺的错误,而不是来自 then 回调的错误,我会推荐 favour .then(…, …) over .then(…).catch(…)。我会写

promise.then(console.log, console.error).finally(() => console.log('Finally'));

其他 more or less obvious 区别在于签名:finally 回调不接收任何参数,p.finally() returns 的承诺将 fulfill/reject 结果与 p 相同(除非回调中出现异常或返回拒绝)。