【JavaScript】JS中的异常处理

2023/02/07 16:59:09

优雅的异常处理方式就像冒泡事件,任何元素可以自由拦截,也可以放任不管交给顶层处理。

try-catch 能捕获到哪些异常

try-catch 语句只能捕获在 try-catch 语句执行期间抛出的异常。

下面这个例子中,由于异常是在定时器中抛出的,抛出异常时 try-catch 语句已经执行完毕(任务队列),所以这个异常未被捕获:

try {
  setTimeout(() => {
    throw Error("请求失败");
  });
} catch (error) {
  console.log("触发异常", error); // 永远不会执行
}

// 程序崩溃
// Uncaught Error: 请求失败

Promise 中的异常

在文章:promise 实现原理解析中已经解析过, Promise 会将接收到的函数整体包裹一层 try-catch 语句后执行,并将错误对象作为 拒绝原因 传递给 reject() 方法,因此只需要用 .catch() 语句就可以获取到错误对象。

Promise.resolve()
  .then(() => {
    throw new Error("请求失败");
  })
  .catch(console.log);

因为在 Promise 内部也是用 try-catch 语句捕获异常,如果是在定时器中抛出的异常同样无法捕获:

Promise.resolve()
  .then(() => {
    setTimeout(() => {
      throw new Error("请求失败");
    });
  })
  .catch(console.log);

Promise 中没有 catch 的异常

如果一个 Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件:

window.addEventListener("unhandledrejection", (event) => {
  console.log("unhandledrejection", event);
});

Promise.reject(1);

全局的事件处理

浏览器环境

浏览器环境中可以通过绑定 onerror 事件来监听抛到全局的异常,但是只能监听到抛出异常事件,不能阻止异常阻断进程。

onerror 事件只能接收到错误对象的 message 信息:

throw new Error(1);

window.onerror = (err) => {
  console.log(err); // Uncaught Error: 1
  console.log(typeof err); // string
};

addEventListener 绑定时可以获取事件对象,事件对象中包含异常的错误对象:

throw new Error(1);

window.addEventListener("error", (event) => {
  console.log(event.error);
  console.log(Object.prototype.toString.call(event.error)); // [object Error]
});

NodeJS 环境

NodeJS 中如果有未捕获的异常会导致系统崩溃,可以通过监听 uncaughtException 事件来监听未捕获的异常,保证应用不会崩溃:

process.on("uncaughtException", (e) => {
  console.error("process error is:", e.message);
});

其他处理可见这篇文章:Node 中如何守护进程

参考

Callback Promise Generator Async-Await 和异常处理的演进open in new window

面试官:请用一句话描述 try catch 能捕获到哪些 JS 异常open in new window

MDN unhandledrejectionopen in new window

nodejs 中的异常错误处理open in new window