promise.prototype.finally 是处理无论成功或失败都必须执行逻辑的理想选择,如关闭 loading;它不接收参数、不影响 promise 状态和返回值,且必定执行,比重复写 then/catch 更简洁健壮。

Promise.prototype.finally 是处理“无论成功还是失败都必须执行”的逻辑的理想选择,比如关闭 loading 状态——它不接收 Promise 的结果(不传参),也不影响 Promise 的状态和返回值,天然适合做清理工作。
为什么 finally 比 then/catch 更合适?
用 then().catch() 需要重复写关闭 loading 的代码,容易遗漏;而 finally 只需写一次,且在 Promise 完成(fulfilled 或 rejected)后**必定执行**,不关心结果,也不会改变链式调用的返回值。
常见错误写法对比:
- ❌ 错误:只在
then里关 loading → 失败时不关闭 - ❌ 错误:
then(close).catch(close)→ 冗余、易漏、可能因 close 抛错中断流程 - ✅ 正确:
fetch(...).finally(close)→ 简洁、健壮、语义清晰
实际使用示例(React + useState)
假设你用 useState 管理 loading 状态:
const [loading, setLoading] = useState(false);
const handleSubmit = () => {
setLoading(true);
api.submitForm(data)
.then(res => console.log('成功', res))
.catch(err => console.error('失败', err))
.finally(() => setLoading(false)); // ✅ 这里统一关闭
};
注意:finally 回调不接收参数,所以不能直接传 setLoading,必须用箭头函数包裹,避免立即执行。
❌ 错误:.finally(setLoading(false))(会立刻执行)
✅ 正确:.finally(() => setLoading(false))
配合 async/await 的写法
在 async 函数中,finally 仍可使用,但需包裹在 Promise 调用之后:
const handleAction = async () => {
setLoading(true);
try {
await api.doSomething();
console.log('成功');
} catch (err) {
console.error('失败');
} finally {
setLoading(false); // ✅ try/catch 的 finally 同样可靠
}
};
注意:这里的 finally 是 try/catch 的语法块,不是 Promise.finally。两者效果一致,但适用场景不同:
– 纯 Promise 链 → 用 .finally()
– async/await + try/catch → 用 try...catch...finally 块更自然
注意事项与边界情况
finally 不会捕获其内部抛出的错误,如果关 loading 时意外报错(比如 DOM 已卸载、setState 在 unmounted 组件上调用),该错误会继续向上冒泡,可能被外层 catch 捕获或导致未处理拒绝。
安全写法建议:
- 在 React 中,关闭 loading 前检查组件是否还存活(如用 useRef 记录 mounted 状态)
- 避免在 finally 中执行可能失败的异步操作(如再发请求)
- finally 中不要 return 值,它不会改变 Promise 结果,但返回 Promise 会导致链式行为变化(一般无需这么做)










