try-catch 需配合 async/await 或 promise 链捕获异步 i/o 错误,应聚焦最小风险单元单独包裹 await 表达式,按网络、数据、存储、业务层分层捕获并差异化处理,finally 仅用于同步清理,并发场景优先用 allsettled。

try-catch 本身不能直接捕获异步 I/O 错误(比如 fetch、localStorage 操作、文件读写等),必须配合 async/await 或 Promise 链显式介入。关键不是“要不要用”,而是“在哪用、怎么分层、如何传递上下文”。
只包裹真正可能失败的 await 表达式
把整个异步流程塞进一个 try 块里,会导致错误定位模糊、副作用失控、异常被意外吞掉。应聚焦最小风险单元,每个 await 单独或按语义分组包裹。
- 网络请求(fetch)单独包裹:判断 HTTP 状态、超时、连接中断
- JSON 解析(res.json())单独处理:避免 SyntaxError 混在 fetch 错误中
- 校验逻辑(如 validateUser(data))移出 try:失败时主动 throw 新 Error,保留业务语义
分层捕获 + 区分错误类型做响应
不同环节的 I/O 失败,应对策略不同。靠 error.name、status、自定义字段(如 error.origin = 'network')分类,而非仅靠 message 字符串匹配。
- 网络层(fetch 拒绝、AbortError):可重试、降级为缓存、提示“请检查网络”
- 数据层(JSON.parse 失败、schema 不匹配):记录结构异常日志、上报监控、返回空态或默认值
- 存储层(localStorage.setItem 失败、QuotaExceededError):清理旧数据后重试,或降级到内存缓存
- 业务层(4xx 响应、权限不足):触发对应 UI 提示、跳转登录页或引导用户操作
避免在 finally 中执行异步操作
finally 块用于同步资源清理(如关闭 loading、释放 AbortController、重置表单状态)。若在里面 await,会阻塞后续执行,且无法保证清理一定完成。
- ✅ 正确:clearLoading(); controller.abort();
- ❌ 错误:await sendErrorLog(err); —— 这会让 finally 变成异步,破坏其“必执行”语义
并发 I/O 场景用 allSettled 或子 Promise 单独 catch
Promise.all 一错全错;而并发请求中部分失败是常态。allSettled 返回每个 Promise 的结果状态,更适合容错场景。
- 对每个 fetch 封装成带独立 try-catch 的子函数,再并行调用
- 或用 allSettled 后遍历 results,分别处理 fulfilled/rejected
- 避免用 Promise.all().catch() 试图统一兜底 —— 会丢失具体哪个请求失败
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











