Promise.prototype.finally S4
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2018
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案为 Promise.prototype 添加了 finally 方法,允许在 Promise 解决(无论是 fulfilled 还是 rejected)时执行回调。它解决了清理操作的需求,例如隐藏旋转器或关闭句柄。回调不接收参数,并且不会改变解决值,除非它抛出异常或返回被拒绝的 Promise。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
Promise.prototype.finally
ECMAScript 提案、规范,以及 Promise.prototype.finally 的参考实现
规范由 @ljharb 起草,遵循 可取消 Promise 提案 的领导。
在 npm 上获取 polyfill/shim。
原理
许多 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/finally(try 当然没有比 Promise.resolve().then 更接近的类比)中类似命名的语法形式的类比。语法上的 finally 只能通过“突然完成”来修改返回值:要么抛出异常,要么提前返回一个值。Promise#finally 将无法修改返回值,除非通过抛出异常(即拒绝 Promise)来创建突然完成——由于无法区分“正常完成”和提前 return undefined,与语法 finally 的平行必须有一个轻微的一致性差距。
我曾简短地考虑过 always 作为替代,因为那不会暗示顺序,但我认为与语法变体的平行是令人信服的。
实现
规范
你可以查看 markdown 格式 的规范,或渲染为 HTML。