在 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/await和try...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 语句,因为这会使代码变得复杂,难以理解和维护。
- 记录异常:在生产环境中,记录异常信息是非常重要的。可以使用日志框架来记录异常信息,以便开发人员能够及时了解和解决问题。