有效,但仅限于 await 的 Promise 被 reject 时;fetch 成功返回 500、业务 code 异常、回调中抛错等均无法自动捕获,需手动校验或封装处理。

有效,但有明确前提:await 必须写在 try 块内,且错误必须来自被 await 的 Promise 的 rejection;它不自动捕获 HTTP 状态码异常、业务错误码或异步回调中未抛出的错误。
为什么只对部分“非同步错误”有效
async/await 是 Promise 的语法糖。当 await 一个被 reject 的 Promise 时,JavaScript 引擎会将其转换为同步风格的异常抛出,此时 try-catch 才能捕获。但以下情况它无能为力:
- fetch() 成功返回 Response 对象(即使 status=500),因为 fetch 本身没 reject —— 这属于 HTTP 层错误,需手动检查
res.ok或res.status - 后端返回 { code: 401, message: "登录过期" },这属于业务约定,不是 JS 异常,必须显式
if (data.code !== 0) throw new Error(...) - setTimeout、addEventListener 回调里抛错,或第三方 SDK 的事件触发中未 reject,这些脱离 await 链的异常无法被捕获
真正起作用的组合方式
try-catch 的有效性依赖于 await 和 Promise rejection 的绑定关系。只有满足这个链条,错误才能落到 catch 中:
-
await Promise.reject(new Error('网络超时'))→ ✅ 可捕获 -
await fetch('/api').then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })→ ✅ 可捕获(因 then 内 throw 触发 Promise reject) -
const p = fetch('/api'); await p;→ ❌ 若 p resolve 了但 status=500,不会进 catch
常见失效场景与应对建议
很多“看似异步”的错误其实不在 try-catch 覆盖范围内,需分层补位:
- 网络层失败(如 DNS 错误、断网):fetch 会 reject,可被 catch 捕获 —— 这是少数原生支持的异步异常
- HTTP 状态异常(4xx/5xx):必须在 await 后立即校验
res.ok,否则静默通过 - 业务数据异常(code ≠ 0):必须解析 JSON 后主动判断并 throw,不能依赖后端“自动报错”
- 多个独立请求:避免共用一个 try 块,否则前一个失败会导致后续请求跳过;可用
.catch(() => defaultValue)单独兜底
更可靠的封装思路
把“可能出问题”的逻辑收口,让 try-catch 真正覆盖所有关键判断点:
- 传入函数而非执行结果(如
() => fetch(...)),避免提前 resolve 导致拦截失效 - HTTP 校验(
!res.ok)、JSON 解析、业务码判断全部放在 try 块内 - 保留原始错误类型(TypeError / SyntaxError / 自定义 Error),方便后续按类型分流处理
- catch 中记录日志、上报、触发提示,但通常仍要
throw err,让调用方决定是否继续处理

















