合理使用 try/catch 包裹 await、错误分类、早期失败、Promise.allSettled 及工具函数封装,可显著降低 async 错误处理复杂性,提升可维护性与语义清晰度。

用 try/catch 包裹 await 表达式,配合明确的错误分类和早期失败策略,能显著降低 async 函数的错误处理复杂性。
只在必要层级捕获错误
避免在每个 await 后都写 try/catch。把逻辑相关的异步操作放在同一个 try 块中,让错误自然冒泡到最合适的处理层(如路由处理器、业务入口或统一错误中间件)。这样既减少嵌套,又保持错误上下文完整。
- 一个函数只负责一类业务(如“创建用户并发送欢迎邮件”),就在这层统一捕获与该业务强相关的错误
- 网络请求、数据库操作等底层调用不自行 catch,除非需要转换错误类型(如把 fetch 错误转为自定义 UserApiError)
- 顶层调用者(如 Express 的 route handler)用 async wrapper 或 .catch() 统一响应 500 或返回结构化错误体
用 reject 或 throw 明确表达失败意图
不要让 async 函数静默吞掉异常,也不要依赖返回 null/undefined 来表示失败。主动 throw 语义清晰的错误实例,便于上层区分处理。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 对已知业务异常(如邮箱已被注册),抛出带 code 和 message 的 Error 子类,例如
throw new ValidationError('EMAIL_EXISTS', '邮箱已被使用') - 避免
if (!data) return null这类模糊路径;改为if (!data) throw new NotFoundError() - 第三方库返回 rejected promise 时,不额外 try/catch 包装,直接让它被外层捕获——这是 Promise 的设计本意
合理使用 Promise.allSettled 替代 Promise.all
当多个异步操作相互独立、某一个失败不应中断其余执行时,用 Promise.allSettled 可避免错误传播带来的控制流混乱。
立即学习“Java免费学习笔记(深入)”;
- 例如“批量发送通知”,一条推送失败不影响其他;用 allSettled 后遍历结果,单独处理 fulfilled/rejected 条目
- 若必须全部成功才继续(如事务型操作),仍用 Promise.all,并在 catch 中做整体回滚或清理
- 注意:allSettled 返回的是 { status, value | reason } 数组,需显式判断每项状态,但换来的是更可控的错误粒度
封装常用异步模式为可复用工具函数
把重复的错误处理逻辑抽离成高阶函数或工具,比如超时控制、重试机制、空值校验,让业务 async 函数聚焦核心逻辑。
- 写一个
withTimeout(promise, ms),超时后自动 reject,避免在每个接口里手动写 setTimeout + race - 实现
retry(fn, options),内部处理 NetworkError 等可重试错误,业务层只需await retry(fetchUser) - 用
safeAwait(返回 [error, result] 元组)适合极少数不想 throw 的场景,但不宜泛滥——它容易掩盖错误边界

















