javascript如何进行错误与异常处理【教程】

JavaScript错误处理靠try...catch、throw和监控机制实现可响应,仅捕获运行时异常,不捕获语法错误或未处理的Promise拒绝;Promise错误需用.catch()或await+try...catch捕获;应按错误类型分类处理,全局监听仅作兜底。

JavaScript 的错误处理不是靠“写得完美”来避免问题,而是靠 try...catchthrow 和恰当的监控机制把不可控变成可响应。

什么时候该用 try...catch

它只捕获**运行时异常(runtime errors)**,比如访问 undefined 的属性、JSON 解析失败、fetch 返回 404 后手动 response.json() 失败等。它不捕获语法错误、Promise 拒绝(unhandled rejection)、或异步回调里的同步错误(除非你在回调里自己包一层)。

  • 适合:DOM 操作前不确定元素是否存

    在、JSON.parse() 输入不可信、调用第三方 SDK 方法但文档没写清边界条件
  • 不适合:给变量赋值写错名(SyntaxError,编译期报错)、忘记 await 导致后续逻辑基于 Promise 对象运行
  • 注意:try...catch 有轻微性能开销,不要包裹整个函数体或高频循环;只包真正可能抛错的最小代码块

Promise 链中的错误怎么捕获?

Promise 构造器内部抛出的错误会被自动转为拒绝状态,但必须用 .catch()await 配合 try...catch 捕获——不能靠外层 try...catch 包住 new Promise(...) 就完事。

常见错误写法:

try {
  new Promise((resolve, reject) => {
    throw new Error('boom'); // 这个错误不会被外层 try 捕获
  });
} catch (e) {
  console.log(e); // 永远不会执行
}

正确做法是:

  • 链式调用末尾加 .catch()fetch('/api').then(r => r.json()).catch(err => {...})
  • async/await 时,在 await 行外层套 try...catch:因为 await 会把 rejected Promise 转成同步抛错
  • 多个并行请求建议用 Promise.allSettled() 而非 Promise.all(),避免一个失败就中断全部

如何区分不同错误类型并做针对性处理?

原生 JS 错误类型如 SyntaxErrorTypeErrorReferenceError 可以直接用 instanceof 判断;自定义错误建议继承 Error 并设 name 字段,方便分类。

示例:

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = 'ValidationError';
  }
}

try {
  throw new ValidationError('用户名不能为空');
} catch (err) {
  if (err instanceof ValidationError) {
    showFormError(err.message);
  } else if (err.name === 'TypeError') {
    logToSentry(err);
  }
}
  • 别只依赖 err.message 做判断——字符串易变、多语言下不可靠
  • 网络请求错误建议统一包装:把 fetch 的 network error、HTTP 状态码、业务 code 分层处理
  • 注意:V8 中 err.stack 是非标准字段,但所有主流环境都支持;若需跨平台兼容,不要把它当核心逻辑依赖

全局错误监听能替代 try...catch 吗?

不能。全局钩子如 window.onerrorwindow.addEventListener('error')process.on('uncaughtException')(Node.js)只作为兜底,用于日志收集和降级,无法阻止错误传播或恢复现场。

  • window.onerror 捕获脚本加载错误、全局同步错误,但不捕获 Promise 拒绝(需 unhandledrejection
  • unhandledrejectionevent.preventDefault() 可阻止控制台报错提示,但不推荐——掩盖问题比记录更危险
  • 真正要“处理”错误(比如弹框、重试、回滚状态),必须在具体执行点附近用 try...catch.catch()

最常被忽略的是:异步操作中错误上下文丢失。比如在 setTimeout 或事件回调里抛错,堆栈里看不到原始调用链——这时候靠 error.stack 不够,得结合 console.trace() 或异步追踪库(如 cls-hooked)补全。