finally 不接收上一个 promise 的返回值,仅用于无条件清理操作;它作用于直接挂载的 promise 实例,位置决定守卫范围;内部异步操作不会被等待,抛错会中断链式流程。

finally 不会接收上一个 Promise 的返回值,别指望它能读到响应数据
finally 的设计目的就是“无论成功失败都执行”,所以它不接收任何参数。你写 promise.finally(() => console.log(data)) 是拿不到 data 的——data 只在 then 或 catch 里有。
常见错误是试图在 finally 里判断状态、重试、或更新 UI 文本(比如“提交成功”/“提交失败”),这会导致逻辑错位。
- 真正需要区分状态的逻辑,必须留在
then和catch中 -
finally只适合关 loading、释放锁、清理定时器、还原表单 disabled 状态这类无条件操作 - 如果清理逻辑依赖结果(比如根据 error.code 决定是否弹 toast),那就不能放
finally,得拆到catch里做
链式调用中 finally 的位置决定它“守哪一段”
finally 作用于它直接挂载的那个 Promise 实例,不是整个链。比如:
fetch('/api/user')
.then(res => res.json())
.finally(() => console.log('这里只守 then 阶段')) // ❌ 如果 fetch 失败,这个不会执行
.catch(err => console.error(err));
正确写法是把 finally 放在最外层 Promise 后:
fetch('/api/user')
.then(res => res.json())
.catch(err => { /* 处理错误 */ })
.finally(() => setLoading(false)); // ✅ 守住整个 fetch + then + catch 流程
- 如果你在
then里又返回了新 Promise,那它的finally只管那个子 Promise - 想统一收口,就让
finally成为链的最后一个方法调用(且前面没有被catch截断) - 注意:如果中间某步抛出未捕获错误,且没写
catch,finally仍会执行——但控制台会报 unhandledrejection
finally 里 throw 或返回 rejected Promise 会中断后续 then
finally 本身不改变 Promise 状态,但它内部抛错或返回 rejected Promise,会让整个链变成 rejected 状态,并跳过后续 then,直接进下一个 catch。
Promise.resolve(1)
.finally(() => { throw new Error('cleanup failed'); })
.then(x => console.log('never runs'))
.catch(err => console.error(err.message)); // 输出 "cleanup failed"
- 这是容易忽略的副作用:你以为只是“清理”,结果意外改变了流程走向
- 绝大多数清理操作不该 throw,应静默吞掉错误(比如
try { localStorage.removeItem('temp') } catch {}) - 如果清理逻辑确实可能失败且需告警,建议用
console.warn而非throw
和 async/await 搭配时,finally 要包在 Promise 外层
你不能对 async 函数直接调用 finally,因为 async 函数返回的是 Promise,但 finally 是原型方法,得显式调用:
async function submitForm() {
setLoading(true);
try {
await fetch('/api/submit', { method: 'POST' });
} finally {
setLoading(false); // ✅ 这是 try/catch 的 finally,不是 Promise.finally
}
}
如果你想用 Promise.prototype.finally,就得这样写:
async function submitForm() {
setLoading(true);
return fetch('/api/submit', { method: 'POST' })
.finally(() => setLoading(false)); // ✅ 返回的新 Promise 会继承原状态
}
- 两者语义不同:try/catch 的
finally是同步语法块,Promise.finally是异步回调 - 在简单场景下,用 try/catch 更直观;需要链式组合多个异步步骤时,
Promise.finally更灵活 - 注意:await 一个带
finally的 Promise,等待的是它最终 resolve/reject 的值,不是finally的返回值
最常被漏掉的一点:finally 不会等它内部的异步操作完成——如果你在 finally 里发请求、写 indexedDB、或 await 某个函数,主 Promise 已经结束了,那些操作变成“游离任务”,失败也不会被上层捕获。真要等清理完成,得自己封装成 Promise 并 return 进去。










