For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-promise-finally.md.
  • 简体中文
  • Promise.prototype.finally S4

    提案概览
    提案速览

    该提案为 Promise.prototype 添加了 finally 方法,允许在 Promise 解决(无论是 fulfilled 还是 rejected)时执行回调。它解决了清理操作的需求,例如隐藏旋转器或关闭句柄。回调不接收参数,并且不会改变解决值,除非它抛出异常或返回被拒绝的 Promise。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    Promise.prototype.finally

    ECMAScript 提案、规范,以及 Promise.prototype.finally 的参考实现

    规范由 @ljharb 起草,遵循 可取消 Promise 提案 的领导。

    npm 上获取 polyfill/shim。

    该提案目前在 流程 中处于 第 4 阶段

    原理

    许多 Promise 库都有一个 "finally" 方法,用于注册一个回调,当 Promise 被解决(无论是 fulfilled 还是 rejected)时调用。这里的基本用例是清理——我想隐藏 AJAX 请求上的“加载”旋转器,或者想关闭我打开的任何文件句柄,或者想记录一个操作已完成,无论它是否成功。

    为什么不使用 .then(f, f)

    promise.finally(func) 类似于 promise.then(func, func),但在几个关键方面有所不同:

    • 当内联创建函数时,你可以传递一次,而不必被迫声明两次或创建一个变量
    • finally 回调不会接收任何参数,因为无法可靠地确定 Promise 是 fulfilled 还是 rejected。这个用例正是当你 不关心 拒绝原因或 fulfillment 值的时候,因此无需提供它。
    • Promise.resolve(2).then(() => {}, () => {})(将以 undefined 解决)不同,Promise.resolve(2).finally(() => {}) 将以 2 解决。
    • 类似地,与 Promise.reject(3).then(() => {}, () => {})(将以 undefined 解决)不同,Promise.reject(3).finally(() => {}) 将以 3 拒绝。

    但请注意:在 finally 回调中抛出异常(或返回一个被拒绝的 Promise)将导致新 Promise 以该拒绝原因被拒绝。

    命名

    坚持使用 finally 的原因很简单:就像 catch 一样,finally 将是 try/catch/finallytry 当然没有比 Promise.resolve().then 更接近的类比)中类似命名的语法形式的类比。语法上的 finally 只能通过“突然完成”来修改返回值:要么抛出异常,要么提前返回一个值。Promise#finally 将无法修改返回值,除非通过抛出异常(即拒绝 Promise)来创建突然完成——由于无法区分“正常完成”和提前 return undefined,与语法 finally 的平行必须有一个轻微的一致性差距。

    我曾简短地考虑过 always 作为替代,因为那不会暗示顺序,但我认为与语法变体的平行是令人信服的。

    实现

    规范

    你可以查看 markdown 格式 的规范,或渲染为 HTML