try-catch本身不提供块级变量隔离,关键在于catch中主动恢复状态、解耦异步与状态更新;真正隔离靠函数作用域+显式状态管理+异步错误不穿透。

try-catch 本身不提供块级变量隔离,它只捕获异常、控制执行流;所谓“避免污染全局状态树”,关键不在 try-catch 的作用域,而在于你**是否在 catch 中主动恢复或重置状态**,以及**是否让异步逻辑与状态更新解耦**。真正起隔离作用的是:函数作用域 + 显式状态管理 + 异步错误不穿透。
用独立作用域封装异步逻辑,避免闭包污染
不要把全局状态(如 Vuex store、Pinia state、或 window 上的变量)直接暴露在异步回调中随意修改。应将每次异步调用及其状态变更封装成独立函数,用参数传入所需状态快照,用返回值或显式 commit 更新:
- ✅ 推荐:调用前 shallowRef 或结构赋值保存当前状态快照,出错时回退到该快照
- ❌ 避免:在 async 函数里直接 this.loading = true; this.data = res; 这类裸赋值,一旦出错,loading 可能卡死为 true
在 catch 中做“状态归位”,而非仅打日志
catch 不是终点,而是状态修复的起点。尤其对 loading、editing、selectedId 等易变 UI 状态,必须显式还原:
- 例如:设置 loading = false;清空 error 字段;恢复上一步的 selectedId;重置表单为初始值
- 若使用 Pinia,可在 action 内部 try-catch,并在 catch 中调用 $patch({ loading: false, error: null })
- 若用 React + useState,应在 useEffect 或事件处理器中捕获异常后,调用对应 setState 回退
用 Promise.finally 或 abortController 控制副作用生命周期
loading 状态这类副作用,不应只依赖 try/catch 分支控制——finally 更可靠,因为它无论成功失败都会执行:
- fetch(...).then(...).catch(...).finally(() => setLoading(false))
- 对可能被中断的请求(如路由跳转),配合 AbortController,在 finally 中 cleanup 相关 pending 标记
- 避免在 then 中设 loading = false,又在 catch 中重复设——容易遗漏或冲突
把“状态树更新”变成纯函数,与副作用分离
真正的隔离来自设计:让状态更新逻辑本身无副作用、可预测、可测试。例如:
- 定义 updateStateOnSuccess(prev, data) → next,updateStateOnError(prev, err) → next
- 在异步处理完成后,统一调用 store.$patch(updateStateOnSuccess(store.$state, res))
- 这样即使某次调用出错,也不会意外修改其他字段;状态演进始终受控于明确定义的函数
不复杂但容易忽略:try-catch 不是状态防火墙,它是你的手动刹车;真正防止污染的,是你每一次更新前的确认、出错后的回滚、以及不让异步逻辑和状态裸耦合的设计习惯。

















