try-catch 不适用于异步错误的盲目包裹,仅对同步代码有效;语法错误、未 await 的 promise 拒绝、异步回调 throw、跨域资源加载失败、fetch 非网络错误均无法捕获。

try-catch 本身不适用于异步错误的“盲目包裹”——它只在同步上下文中生效,对 async/await 的异常捕获必须严格满足执行时机和作用域条件。用错位置、包得过宽或替代方案更优时,硬加 try-catch 反而增加维护成本、掩盖真实问题。
它根本捕获不到的场景
以下错误类型,无论你把 try-catch 写得多严密,都完全无效:
-
语法错误(SyntaxError):比如
const obj = { a: 1, }少了个逗号,代码根本无法解析执行,try-catch 还没机会运行; -
Promise 拒绝但未 await 的情况:如
fetch('/api').then(...)放在 try 块里,但没 await,拒绝会被静默吞掉或触发 unhandledrejection; -
异步回调里的 throw:例如
setTimeout(() => { throw new Error('boom') }, 100),外层 try-catch 完全无感; -
跨域资源加载失败(如 script、img):这类错误不抛 JS 异常,需监听
error事件而非靠 catch; -
fetch 返回 4xx/5xx 状态码:它不会 reject,而是 resolve 一个 response 对象,错误需手动检查
!res.ok后主动 throw。
不该用 try-catch 的业务逻辑场景
即使技术上能捕获,也不代表“该捕获”。关键看责任归属和处理意图:
-
底层工具函数(如封装的 API 请求):应让错误向上冒泡,由具体业务层决定如何提示用户、重试或跳转,而不是在 fetch 封装里就
catch(e) { message.error('请求失败') }; -
全局可兜底的错误:Vue 的
config.errorHandler、React 的ErrorBoundary、Node.js 的unhandledRejection监听,已覆盖大部分未捕获异常,重复加 try-catch 属于冗余防御; -
仅需标记状态、不中断流程的操作:比如“记录用户行为日志”,失败不影响主流程,用
.catch(() => {})或忽略更轻量,不必引入 try-catch 块; -
高频调用函数(如渲染循环、滚动监听):V8 会因 try-catch 禁用部分优化,性能敏感路径应优先用
typeof、?.、??等防御性写法代替。
有更优雅替代方案的时候
为每个 await 都配一套 try-catch,代码迅速臃肿。这些方式往往更清晰:
-
用
.catch()链式收口:适合单个请求只需简单降级(如 fallback 数据),避免打断后续逻辑; -
引入
await-to-js或自定义 to() 工具:返回[error, data]元组,用 if 判断替代 try-catch 块,尤其适合多层嵌套 await 场景; - 统一请求拦截 + 错误分类处理:在 axios/fetch 封装层根据 status、响应结构自动映射业务错误码,上层直接消费语义化错误,不用每处都写分支判断。
真正要问的不是“能不能捕获”,而是“该不该在这里捕获”“捕获后是否真能处理”“有没有漏掉异步分支”。不加 try-catch 不等于放任错误,而是把错误交给更合适的位置和方式去应对。











