应统一错误形态、解耦业务判断与异常捕获,用结构化结果({error, result})包装每个await,配合allSettled和分层错误处理实现可控、可观、可恢复的异步流。

关键在于统一错误形态、解耦业务判断与异常捕获,避免“一个错全盘崩”或“错误被吞没”。不需要每个 await 都套 trycatch,也不该让 Promise.reject 漏到顶层。
用结构化结果包装每个 await
把每个异步调用的结果标准化为 { error, result } 形式,错误不再抛出,而是作为值返回。这样业务逻辑可主动判断:成功走正常流程,失败走降级或提示。
- 可用
await-to-js库:import to from 'await-to-js',然后[err, data] = await to(fetch('/api/user')) - 也可手写轻量封装:
const to = p => p.then(res => [null, res]).catch(err => [err, null]) - 后续操作不依赖
try/catch,而是检查if (err) { ... },逻辑更线性
并发请求用 allSettled 而非 all
Promise.all() 遇到任一失败就中断,无法获取其余结果;而 Promise.allSettled() 总是返回所有任务的终态(fulfilled 或 rejected),适合需要“尽力而为”的场景。
- 例如批量拉取用户头像、配置项、权限列表:即使某一项超时或 404,其他数据仍可用
- 结果形如:
[{ status: 'fulfilled', value }, { status: 'rejected', reason }],逐项解析即可 - 配合结构化包装,可统一提取成功数据、聚合失败原因用于上报或重试
错误分类处理,不混为一谈
网络错误、服务端业务错误(如 401、403、422)、前端逻辑错误,应区分对待。一致性不是“都用 catch 处理”,而是“每类错误有明确归宿”。
- 网络层错误(超时、断网):触发 loading 中止 + 用户提示 + 自动重试(可选)
- 业务错误(如 token 过期、权限不足):跳转登录页或弹窗引导,不计入错误日志主通道
- 未预期错误(如 JSON 解析失败、字段缺失):捕获后打点上报,保留原始堆栈,便于定位
- 避免在 catch 里写
alert(e)或静默吞掉,至少记录console.error
顶层兜底 + 明确错误传播路径
不是所有错误都要在每个 async 函数里终结。合理分层:底层负责转换、中间层负责分类、顶层负责呈现与恢复。
- API 请求函数统一做
fetch封装,自动处理 4xx/5xx,将业务错误转为结构化对象(含 code、message、data) - 页面级 async 方法(如
onLoad)只做顶层 trycatch,用于展示 loading 状态和兜底 UI - 全局监听
unhandledrejection,捕获漏网之鱼,防止白屏或静默失败 - 拒绝直接在组件内写
await xxx().catch(...),破坏调用链,也难统一策略

















