try-catch 不能直接捕获并发异常,需用 promise.allsettled 隔离局部失败、单个 await + 最小粒度 try-catch 实现差异化恢复、fire-and-forget 必须内部 catch、封装 to() 函数将错误转为返回值。

try-catch 本身不能直接“捕获并发异常”,它只响应被 await 的 Promise 拒绝;而并发执行(如 Promise.all、Promise.allSettled)中的局部失败,需靠组合策略隔离处理——不是靠嵌套 try-catch,而是靠 Promise 状态控制 + 显式错误分支。
用 allSettled 替代 all,让每个请求独立成败
Promise.all 遇到任一拒绝就整体失败,无法拿到其余成功结果;allSettled 则始终返回全量状态数组,天然支持局部异常识别:
- 每个元素是 { status: 'fulfilled' | 'rejected', value | reason },无需 try-catch 就能区分成功/失败
- 适合并行获取用户资料、头像、配置等弱依赖项,失败一项不影响其他
- 示例:const results = await Promise.allSettled([fetchUser(), fetchAvatar(), fetchConfig()]);
对单个 await 步骤做最小粒度 try-catch
若某项并发任务需差异化恢复(如重试、降级、上报),应将其单独 await 并包裹 try-catch,而非把所有 await 塞进一个大块里:
- 避免“一个失败全盘中断”,也避免“所有都包一层”导致冗余嵌套
- 例如:获取用户主数据失败后,可 fallback 到本地缓存;但头像加载失败只需静默忽略
- 关键:每个 await 对应一个语义明确的业务单元,catch 中只处理该单元特有的恢复逻辑
避免未处理 Promise 拒绝引发 unhandledrejection
即使用了 allSettled 或局部 try-catch,仍可能漏掉某些 Promise:
- fire-and-forget 式调用(如日志上报、埋点)必须内部自行 catch,不能依赖外层
- 事件监听器中启动的 async 操作,若组件已卸载,需提前检查有效性(React 用 ref,Vue 用 isMounted)
- 全局监听 window.addEventListener('unhandledrejection') 可兜底发现遗漏,但不应作为主要手段
封装 to() 工具函数,把异常转为返回值
类似 Go 的错误处理风格,用函数统一解构 Promise 状态,让错误变成数据流的一部分:
- function to(p) { return p.then(v => [null, v]).catch(e => [e, null]); }
- const [err, data] = await to(fetch('/api/user')); if (err) { /* 处理 */ }
- 优势:消除 try-catch 语法噪音,便于链式判断,也利于 TypeScript 类型推导











