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; })
);
};
</font><p>说明:</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/c1c2c2ed740f" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">Java免费学习笔记(深入)</a></a>”;</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill7957" title="js2java"><img
src="https://img.php.cn/upload/skill/000/000/081/179178140274370.jpg" alt="js2java" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill7957" title="js2java">js2java</a>
<p>JavaScript 到 Java 全栈翻译助手,专为前端开发者学习 Java 或快速实现后端业务逻辑而设计。当用户提到以下场景时必须使用此技能: - "帮我把这段 JS 代码转成 Java" - "用 Java 怎么写这个逻辑" - "我习惯用 JS 写,想翻译成 Java" - "教我 Java,我要写后端接...</p>
</div>
<a href="/xiazai/skill7957" title="js2java" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><ul><li>用 <code>this.then</code> 捕获前序 Promise 的成功/失败</li><li><code>onFinally()</code> 被包裹在 <code>Promise.resolve(...).then(...)</code> 中,确保它异步执行且可处理返回 Promise 的情况</li><li>成功分支:先执行 <code>onFinally</code>,再把原始 <code>value</code> 透传</li><li>失败分支:先执行 <code>onFinally</code>,再用 <code>throw reason</code> 原样抛出,避免被吞掉</li></ul><H3>3. 为什么不能直接 return value / throw reason?</H3><p>比如这样写是错的:</p><font color="#666"><pre class="brush:php;toolbar:false;">
// ❌ 错误: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'

















