浅谈 JavaScript中 的异常捕获和处理

215 阅读4分钟

在 JavaScript 开发中,异常捕获可以帮助我们提高代码的稳定性和可靠性。今天就让咱来深扒一下 JS 里的异常捕获机制,特别是异步代码里的那些事儿。

为什么要捕获并处理异常

一、异常捕获,为啥这么重要?

  • 让代码更扛造:现实中,各种意外情况都能让代码出错。有了异常捕获,就算出错也能稳住阵脚,避免程序崩掉,这不就增强了代码的稳定性嘛!
  • 用户体验杠杠的:要程序运行时突然崩溃,那用户体验能好才怪。异常捕获能在出错时给用户来个友好的提示,体验自然就上去了。
  • 调试维护轻松搞定:代码一报错,异常捕获就能给出详细的错误信息,比如啥类型、啥消息、在哪儿出的错。这些信息可是咱开发人员的宝贝,调试维护起来轻松多了!

二、JS 里的异常类型,就两种

  • 语法错误(SyntaxError):代码写得不对,违反了 JS 的规矩,比如括号、分号没写对。
  • 运行时错误(RuntimeError):程序运行时出的错,像访问没定义的变量、数组越界、类型不匹配这种。

异常处理的三种场景

一、同步代码里的异常捕获

同步代码里,咱就用 try...catch...finally来搞定异常。

  • try块:把可能出错的代码放这儿。
  • catch块:要是 try块里的代码抛异常了,就执行这儿的代码。还能接个参数,就是那个异常对象,从中能获取详细的错误信息。
  • finally块:不管 try块里的代码出不出错,这儿的代码都得执行。通常用来清理资源,比如关文件、断数据库连接啥的。
try {
  // 可能会抛出异常的代码
  const result = a / b;
} catch (error) {
  // 处理异常的代码
  console.error("发生了错误:", error.message);
} finally {
  // 无论是否发生异常都会执行的代码
  console.log("finally 块中的代码被执行");
}

在上面的示例中,如果变量 a 或 b 未定义,或者 b 的值为 0,那么在执行 const result = a / b;时就会抛出异常。这个异常将被 catch 块捕获,并在控制台输出错误消息。无论是否发生异常,finally 块中的代码都会被执行。

二、异步代码里的异常捕获

异步代码里,因为执行时间不确定,不能直接用 try...catch。得这么处理:

  • .then().catch()方法:对付返回 Promise 的异步函数,用 .then()处理成功的结果,用 .catch()处理异常。
  • async/awaittry...catch:在异步函数里用 async/await语法,外面再用 try...catch捕获异常。
  • 全局异常处理:用 process.on('unhandledRejection')process.on('uncaughtException')来处理那些没被捕获的 Promise 异常和同步代码里的未捕获异常。
asyncFunction()
  .then((result) => {
    // 处理成功的结果
  })
  .catch((error) => {
    // 处理异常
    console.error("发生了错误:", error.message);
  });

使用 async/await 和 try...catch:可以在异步函数中使用 async/await 语法,并在外部使用 try...catch 语句来捕获异常。

async function callAsyncFunction() {
  try {
    const result = await asyncFunction();
    // 处理成功的结果
  } catch (error) {
    // 处理异常
    console.error("发生了错误:", error.message);
  }
}

全局异常处理:可以使用 process.on('unhandledRejection')和 process.on('uncaughtException')来处理未捕获的 Promise 异常和同步代码中的未捕获异常。

process.on("unhandledRejection", (error) => {
  console.error("未处理的 Promise 拒绝:", error.message);
});

process.on("uncaughtException", (error) => {
  console.error("未捕获的异常:", error.message);
  process.exit(1);
});

三、同步方法块里返回异步方法的异常捕获

这种情况,得在异步方法的 .then().catch()里处理异常。try...catch在同步代码块里只能捕获同步代码的异常,异步的得另想办法。 当在同步方法块中返回一个异步方法时,可以使用以下方法来捕获异常:

function syncFunctionReturningAsync() {
  return asyncFunction();
}

try {
  syncFunctionReturningAsync()
    .then((result) => {
      // 处理成功的结果
    })
    .catch((error) => {
      // 处理异常
      console.error("发生了错误:", error.message);
    });
} catch (error) {
  // 这里不能捕获异步方法中的异常
  console.error("同步代码中的异常:", error.message);
}

在上面的示例中,syncFunctionReturningAsync 函数返回一个异步函数。在 try...catch 语句中,只能捕获同步代码中的异常,不能捕获异步方法中的异常。要捕获异步方法中的异常,需要在异步方法的.then()和.catch()方法中进行处理。

最后寄语

  • 只捕获你能处理的异常:不要捕获所有的异常,只捕获你能够处理的异常。如果你捕获了一个无法处理的异常,那么最好将其重新抛出,以便更高层次的代码能够处理它。
  • 提供有意义的错误信息:当抛出异常时,提供有意义的错误信息,以便开发人员能够快速定位和解决问题。
  • 使用 finally 块清理资源:在 finally 块中清理资源,如关闭文件、释放数据库连接等,以确保资源得到正确释放。
  • 避免在 catch 块中使用 try...catch 语句:在 catch 块中尽量避免使用 try...catch 语句,因为这会使代码变得复杂,难以理解和维护。
  • 记录异常:在生产环境中,记录异常信息是非常重要的。可以使用日志框架来记录异常信息,以便开发人员能够及时了解和解决问题。