最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何用 Promise.prototype.finally 统一处理不管请求成功还是失败都要隐藏的骨架屏
时间:2026-07-19 11:06:49 编辑:袖梨 来源:一聚教程网
Promise.prototype.finally 适合隐藏骨架屏,因为它在 Promise settled 后必执行,不干扰返回值且不吞错误;需置于链末端或 try/finally 块中,避免竞态与错误覆盖。
Promise.prototype.finally 为什么适合隐藏骨架屏
因为 finally 不关心上一个 Promise 是 fulfilled 还是 rejected,只要状态 settled 就执行,天然契合“请求结束就收起骨架屏”的语义。它不接收参数,不会干扰链式返回值,也不会意外吞掉错误——这点比在 then 和 catch 里重复写隐藏逻辑更安全。
在 fetch 请求中正确使用 finally 隐藏骨架屏
常见错误是把 finally 放错位置,比如写在 catch 后面却忘了 then 也可能抛错(例如 response.json() 解析失败),导致骨架屏卡住。正确做法是让 finally 紧跟在最终的 Promise 链末端:
showSkeleton();fetch('/api/data') .then(res => { if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); }) .then(data => render(data)) .catch(err => handleError(err)) .finally(() => hideSkeleton());
注意:如果中间用了 async/await,finally 不能直接链在 await 表达式后,得包一层 Promise:
showSkeleton();try { const res = await fetch('/api/data'); const data = await res.json(); render(data);} catch (err) { handleError(err);} finally { hideSkeleton();}
finally 中修改状态可能引发竞态问题
当多个并发请求共用同一个骨架屏开关(比如全局 isLoading 变量),直接在每个请求的 finally 里设 isLoading = false 会导致后完成的请求覆盖先完成的,骨架屏提前消失。解决方法:
- 用计数器:发起请求前
pendingCount++,finally里pendingCount--,仅当pendingCount === 0时隐藏 - 用 AbortController 配合状态标记,或改用 React Query / SWR 等自带 loading 状态管理的库
- 避免共享状态,每个组件维护自己的
isPending,靠 UI 层统一控制显示逻辑
finally 不会阻止错误向上传播,但容易误以为它会
这是最常被忽略的一点:finally 里的代码执行完后,原始 rejection 仍会继续冒泡。如果你在 finally 里写了 throw 或返回 rejected Promise,它会覆盖原错误;但什么也不做,就不会影响错误流向。所以以下写法是安全的:
fetch('/api/data') .then(handleSuccess) .catch(handleError) .finally(() => hideSkeleton()); // ✅ 原错误仍能被外层 try/catch 捕获
而这样会出问题:
.finally(() => { hideSkeleton(); return Promise.reject(new Error('finally broke it')); // ❌ 覆盖了原始错误})
实际项目中,只要 finally 体里只做副作用(如 DOM 更新、日志、清理定时器),就不需要担心错误流被破坏。
相关文章
- 苹果折叠屏爆料汇总:售价超两万,比例阔折叠 07-30
- 纪念碑谷3 纪念碑谷3手游玩法详解与体验评测 07-30
- 晴空双子金卡阵容推荐 晴空双子高性价比氪金养成指南 07-30
- 大周列国志全新派系系统 07-30
- 兔小萌世界甜系小房间搭建指南 兔小萌世界高颜值甜系房间布置全流程详解 07-30
- 大周列国志全新剧本包西汉剧本包 07-30