JavaScript 错误处理需区分同步/异步错误:try...catch 仅捕获同步运行时错误;异步错误须用 .catch()、await 配合 try 或 unhandledrejection 监听;error.stack 调试需容错,source map 助力定位;全局兜底不能替代业务层明确错误处理。
JavaScript 错误处理不是加个 try...catch 就万事大吉,关键看错误是否真被拦截、是否可定位、是否影响后续逻辑。
哪些错误能被 try...catch 捕获
try...catch 只捕获同步运行时错误(比如 TypeError、ReferenceError),对以下情况完全无效:
- 异步代码中的错误(如
setTimeout、Promise内部抛出的错误) - 事件回调里的错误(如
addEventListener中的throw) - 语法错误(
SyntaxError)——这类错误在解析阶段就崩溃,根本进不了try块 - 资源加载失败(如
script标签 404)
示例:try { setTimeout(() => { throw new Error('boom') }, 0); } catch(e) { } —— 这个 catch 不会执行。
异步错误必须单独处理
Promise 链中错误需用 .catch() 或 await 配合 try...catch;但要注意 async/await 的 try 只包裹当前函数体,不跨函数调用边界。
- 使用
await时,必须确保被await的是 Promise,否则不会进入catch -
Promise.all([])遇到任一
拒绝即 reject,若要收集全部结果(含失败),得用
Promise.allSettled([]) - 未处理的 Promise rejection 会触发
unhandledrejection全局事件,建议监听并记录:window.addEventListener('unhandledrejection', e => console.error(e.reason))
error.stack 是调试核心,但别直接依赖格式
浏览器中 error.stack 提供调用链,但各环境输出不一致(Chrome 含列号,Safari 不稳定,Node.js 默认无列号)。不要用正则硬切 stack 字符串来提取文件名或行号。
- 优先用
console.error(error)输出完整对象,浏览器控制台会自动展开堆栈 - 做错误上报时,可用
error.name+error.message+error.stack三元组,但需容错处理stack为空或格式异常的情况 - 构建时启用 source map 并部署到线上,才能把压缩后代码映射回源码位置
全局错误兜底不能替代局部处理
window.onerror 和 window.addEventListener('error') 能捕获资源加载失败、脚本执行错误等,但它们无法获取原始 error 对象(只有消息、文件、行号、列号字符串),且无法阻止默认行为(比如图片加载失败仍显示断裂图标)。
-
window.onerror不捕获 Promise rejection,必须配合unhandledrejection - 两者都属于“最后防线”,不能代替业务层的明确错误分支(例如 API 返回 401 应跳登录页,而不是只打日志)
- 若同时注册了多个
error监听器,注意执行顺序不可控,避免重复上报
真正难的不是写 catch,而是判断该不该吞掉错误、该不该重试、该不该降级、该不该通知用户——这些决策藏在业务逻辑里,和语法无关。









