promise.prototype.finally 的核心是不改变原 promise 状态和值:无论 fulfilled 或 rejected,均原样透传结果;onfinally 异步执行且需等待其 settle 后再传递原始 value 或 reason,若其抛错则覆盖原结果。

Promise.prototype.finally 的核心要求是:不改变原始 Promise 的状态和值,无论前面是 fulfilled 还是 rejected,都要把结果原样传下去。手写时关键在于——不能在 finally 回调里 return 或 throw 无关值,也不能直接 resolve/reject 新值。
1. finally 不应影响链式结果
它只是“收尾动作”,类似 try-catch-finally 中的 finally:执行完后,把上一步的 value 或 reason 继续往下传。所以手写时要:
- 在内部
then的两个回调中,都执行用户传入的onFinally函数(无参调用) - 两个回调都返回一个
Promise.resolve(value)或Promise.reject(reason),保持原状态和原值 - 特别注意:如果
onFinally抛错,该错误会覆盖原结果,变成 rejected —— 这是符合规范的行为
2. 手写实现示例(兼容 Promise A+)
以下是一个简洁可靠的实现:
Promise.prototype.finally = function(onFinally) {
return this.then(
value => Promise.resolve(onFinally()).then(() => value),
reason => Promise.resolve(onFinally()).then(() => { throw reason; })
);
};
说明:
- 用
this.then捕获前序 Promise 的成功/失败 -
onFinally()被包裹在Promise.resolve(...).then(...)中,确保它异步执行且可处理返回 Promise 的情况 - 成功分支:先执行
onFinally,再把原始value透传 - 失败分支:先执行
onFinally,再用throw reason原样抛出,避免被吞掉
3. 为什么不能直接 return value / throw reason?
比如这样写是错的:
// ❌ 错误:onFinally 返回 Promise 时会被当作新结果
.then(value => { onFinally(); return value; })
<p>// ❌ 更错:throw reason 会触发微任务链中的 reject 处理,但没包裹 Promise.resolve(onFinally())
.then(value => { onFinally(); return value; }, reason => { onFinally(); throw reason; })</p>问题在于:onFinally 可能返回 Promise,必须等它 settle 后再继续传递原值,否则会丢失异步时机或导致值被覆盖。
4. 实际链式效果对比
✅ 正确行为:
Promise.resolve(42)
.finally(() => console.log('done')) // 先打印
.then(x => x * 2) // x === 42,结果是 84
✅ 失败时也透传:
Promise.reject('oops')
.finally(() => console.log('cleanup')) // 先打印
.catch(err => err.toUpperCase()) // err === 'oops',结果是 'OOPS'
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











