try...catch仅捕获同步执行中抛出的Error实例,无法捕获异步错误、Promise拒绝及事件回调异常;HTTP状态码不触发JS异常,需手动检查response.ok等。

try...catch 能捕获哪些错误
它只捕获同步执行中抛出的 Error 实例(包括 throw new Error()、原生异常如 ReferenceError、TypeError),对异步错误(如 setTimeout 里的 throw)、Promise 拒绝(Promise.reject())、事件回调中的异常默认无能为力。
常见误判:把 fetch 请求失败当成网络错误直接 try,结果发现 404 或 500 响应仍进 then —— 因为 HTTP 状态码不触发 JS 异常,必须手动检查 response.ok 或 response.status 后再 throw。
正确包裹同步逻辑的边界在哪
不要把整个函数体包进一个 try,而要聚焦在「可能出错且你有明确恢复策略」的代码段。比如解析 JSON、访问深层嵌套属性、调用外部 SDK 的同步方法。
-
JSON.parse(input)必须 try,否则非法字符串直接崩掉脚本 -
obj.user.profile.name在不确定obj或中间字段存在时,用 try 比一堆&&更直白(但性能略低,简单场景优先用可选链obj?.user?.profile?.name) - 调用
localStorage.setItem()前不用 try —— 它本身不抛异常,但写满配额时后续操作可能失败,这种要靠try/catch+localStorage.length监控
catch 中该做什么,不该做什么
catch 不是日志收容所。重点做三件事:记录上下文、降级处理、重新抛出不可恢复的错误。
容易踩的坑:
- 只写
console.error(e)就完事 —— 缺少时间戳、模块名、输入参数,线上无法定位 - 吞掉错误却不返回默认值,导致调用方拿到
undefined却不知为何 - 在 catch 里又调用另一个可能出错的函数(比如写日志时连不上 Sentry),没二次 try,引发级联崩溃
- 对
TypeError和SyntaxError一视同仁 —— 前者可能是数据脏,后者大概率是代码 bug,后者该立刻报监控而非静默处理
示例:安全解析 JSON
function safeParse(jsonStr) {
try {
return JSON.parse(jsonStr);
} catch (e) {
if (e instanceof SyntaxError) {
console.warn('[safeParse] Invalid JSON', { input: jsonStr.slice(0, 100), error: e.message });
return null;
}
throw e; // 其他错误(如内存溢出)不拦截
}
}
async/await 场景下怎么写才不漏错
async 函数内部的 try...catch 只能捕获同步代码和 await 后已 reject 的 Promise。漏掉的情况很典型:
-
await fetch(url)成功返回 Response 对象,但没检查res.ok就直接await res.json()—— 此时res.json()可能因响应体非 JSON 而 reject,但外层 try 已退出 - 多个 await 并行时(
await Promise.all([p1, p2])),一个失败会导致整个 all reject,但你可能想分别处理每个请求的错误 - 忘记给
fetch加超时,网络卡死时 await 永远不结束,try 块形同虚设
推荐模式:每个 await 后立即判断,或封装成带错误分类的工具函数
async function fetchWithStatus(url) {
const controller = new AbortController();
setTimeout(() => controller.abort(), 8000);
try {
const res = await fetch(url, { signal: controller.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (e) {
if (e.name === 'AbortError') throw new Error('Request timeout');
throw e;
}
}
最常被忽略的是错误分类粒度 —— 同一个 catch 块里混着处理网络中断、服务端 500、客户端数据格式错误,最后降级逻辑全乱套。按错误类型分层捕获,比堆 if/else 判断 e.message 字符串靠谱得多。

















