try-catch 在异步中需与 await 节奏对齐:仅 await 在 try 内触发的 Promise 拒绝才被捕获;漏 await、递归未逐层包裹、共用 try 导致连锁中断、finally 未 await 均引发错误逃逸或资源泄漏。

try-catch 在异步编程中不是“包一层就万事大吉”,它必须与任务调度节奏对齐——只有被 await 的 Promise 拒绝,且该 await 位于 try 块内,错误才会进入 catch;否则异常会漏捕、中断重试、甚至触发 unhandledrejection。
async/await 场景下:await 必须在 try 内
async 函数返回 Promise,await 是语法糖,本质把后续逻辑塞进 .then()。但 try-catch 只捕获同步抛出或 await 触发的错误:
- ✅ 正确:try { const res = await fetch(url); ... } —— fetch 拒绝时,错误同步抛到 catch
- ❌ 错误:try { fetch(url); } —— fetch 返回 Promise 后立即退出 try,后续 reject 不受保护
- ⚠️ 隐患:漏写 await(如 const p = api(); 未 await p),等于把 Promise 当同步值处理,错误完全逃逸
异步递归任务:每层都需独立 try-catch
递归调用若脱离当前 try 作用域,就失去保护。常见错误是只在外层包一次,结果重试失败后异常直接冒泡:
- 正确做法:每次递归前确保其 await 被 try 包裹,例如在 catch 中 await 后再 return 新递归调用
- 资源清理建议加 finally:如 clearTimeout、移除监听器、释放锁,避免因重试堆积泄漏
- 状态敏感场景(如 token 过期)需在 catch 中更新上下文,否则递归会重复用旧凭证失败
多个异步操作:按业务粒度拆分保护
共用一个 try-catch 容易导致连锁中断——前一个 await 失败,后面本可独立执行的任务也被跳过:
立即学习“Java免费学习笔记(深入)”;
- 推荐为每个关键请求单独兜底:user.catch(() => DEFAULT)、posts.catch(() => [])
- 强依赖链(如先登录再拉数据)才共用 try;弱依赖或可降级操作,应各自处理
- 细粒度判断错误类型:TypeError(网络断开)可重试,401 应刷新 token,404 可展示空态而非报错
finally 的真实作用:等所有 await 结束再执行
finally 不会自动等待异步任务,必须 await 才能确保清理时机准确:
- ✅ try { await db.query(); await cache.set(); } finally { await db.close(); } —— 关闭等前面全完成
- ❌ try { db.query(); cache.set(); } finally { db.close(); } —— finally 立即执行,查询还在跑
- ⚠️ finally 内 await 若抛新错,会覆盖原异常;非关键清理(如日志上报)可用 fire-and-forget 避免阻塞



















