JavaScript怎样进行错误处理【教程】

JavaScript 错误处理需区分同步/异步错误:try...catch 仅捕获同步运行时错误;异步错误须用 .catch()、await 配合 try 或 unhandledrejection 监听;error.stack 调试需容错,source map 助力定位;全局兜底不能替代业务层明确错误处理。

JavaScript 错误处理不是加个 try...catch 就万事大吉,关键看错误是否真被拦截、是否可定位、是否影响后续逻辑。

哪些错误能被 try...catch 捕获

try...catch 只捕获同步运行时错误(比如 TypeErrorReferenceError),对以下情况完全无效:

  • 异步代码中的错误(如 setTimeoutPromise 内部抛出的错误)
  • 事件回调里的错误(如 addEventListener 中的 throw
  • 语法错误(SyntaxError)——这类错误在解析阶段就崩溃,根本进不了 try
  • 资源加载失败(如 script 标签 404)

示例:try { setTimeout(() => { throw new Error('boom') }, 0); } catch(e) { } —— 这个 catch 不会执行。

异步错误必须单独处理

Promise 链中错误需用 .catch()await 配合 try...catch;但要注意 async/awaittry 只包裹当前函数体,不跨函数调用边界。

  • 使用 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.onerrorwindow.addEventListener('error') 能捕获资源加载失败、脚本执行错误等,但它们无法获取原始 error 对象(只有消息、文件、行号、列号字符串),且无法阻止默认行为(比如图片加载失败仍显示断裂图标)。

  • window.onerror 不捕获 Promise rejection,必须配合 unhandledrejection
  • 两者都属于“最后防线”,不能代替业务层的明确错误分支(例如 API 返回 401 应跳登录页,而不是只打日志)
  • 若同时注册了多个 error 监听器,注意执行顺序不可控,避免重复上报

真正难的不是写 catch,而是判断该不该吞掉错误、该不该重试、该不该降级、该不该通知用户——这些决策藏在业务逻辑里,和语法无关。