finally 不接收 promise 的 resolve 或 reject 值,仅用于无参副作用;需配合计数器管理全局 loading;链式调用中须确保每个请求都覆盖 finally;ie11 需 polyfill 或用 then/ensure 降级。

finally 不会接收 Promise 的 resolve 或 reject 值,别试图在里面读响应数据
finally 的核心作用是“无论成功失败都执行”,它不接收任何参数。常见错误是写成 promise.finally(res => hideLoading()) —— 这里的 res 实际是 undefined,且会报 res is not defined(因为 finally 回调无入参)。真正要取响应体或错误信息,必须在 then 或 catch 里处理。
实际用法只有这一种安全形式:
api.getData().then(data => {
// 处理 data
}).catch(err => {
// 处理 err
}).finally(() => {
hideLoading(); // ✅ 正确:无参数,只做副作用
});
全局 Loading 遮罩需配合状态管理,避免多次 hide 导致遮罩提前消失
如果多个请求并发、且都调用 finally 执行 hideLoading(),可能在第一个请求结束时就关掉了遮罩,而其他请求还在 pending —— 这不是 finally 的问题,而是遮罩逻辑没做计数。
- 推荐用一个简单计数器:
loadingCount,每次请求前showLoading()时 +1,finally里 -1,仅当loadingCount === 0才真正隐藏 - 不要依赖「所有请求都挂同一个
finally」来控制遮罩,HTTP 请求彼此独立,生命周期不一致 - 若用 Axios,可在
interceptors.request里showLoading(),在interceptors.response和interceptors.request.use(..., error => {...})中统一hideLoading(),但注意响应拦截器的error分支也要调用(网络失败、超时等不会进response拦截器)
finally 在链式调用中只对当前 Promise 生效,别漏掉深层嵌套的请求
下面这种写法,外层 finally 只覆盖 fetchUser(),不覆盖 fetchProfile():
fetchUser().then(user => {
return fetchProfile(user.id); // ✅ 这个 Promise 没被 finally 包裹
}).finally(() => hideLoading());
结果是用户数据拿到后遮罩就关了,但头像还没加载完。正确做法是让每个发起网络请求的 Promise 都有自己的 finally,或统一收口到请求封装函数里:
function requestWithLoading(url) {
showLoading();
return fetch(url).finally(() => hideLoading());
}
再或者用 async/await + try/finally(更直观):
async function loadPage() {
showLoading();
try {
const user = await fetchUser();
const profile = await fetchProfile(user.id);
render(user, profile);
} finally {
hideLoading(); // ✅ 覆盖整个 try 块内所有 await
}
}
IE11 不支持 finally,Polyfill 或降级方案得提前检查
Promise.prototype.finally 在 IE11 完全不可用,即使你用了 Babel,也得确保引入了 core-js/stable/promise/finally 或类似 polyfill。否则生产环境直接报 TypeError: Promise.prototype.finally is not a function。
如果无法加 polyfill(比如遗留系统限制),可用 .then(finallyFn, finallyFn) 代替,但要注意:
- 不能直接写
then(hideLoading, hideLoading),因为hideLoading可能抛错,导致链中断 - 稳妥写法是
then(() => hideLoading(), () => hideLoading()) - 更推荐封装一个工具函数:
function ensure(fn) { return () => { try { fn(); } catch (e) {} } },然后用then(ensure(hideLoading), ensure(hideLoading))
真正容易被忽略的是:很多团队只测 Chrome,上线后 IE 用户白屏或功能异常,却以为是业务逻辑问题,其实卡在 finally 报错上。










