# Nodejs 事件
# 如何处理异常
uncaughtException 事件
Nodejs 可以通过 try-catch 来捕获异常。如果异常未捕获,则会一直从底向事件循环冒泡。如是冒泡到事件循环的异常没被处理,那么就会导致当前进程异常退出。
根据文档,可以通过监听 process 的 uncaughtException 事件,来处理未捕获的异常
process.on("uncaughtException", (err, origin) => {
console.log(err.message);
});
const a = 1 / b;
console.log("abc"); // 不会执行
上面的代码,控制台的输出是:b is not defined
。捕获了错误信息,并且进程以 0 退出。开发者可以在 uncaughtException 事件中,清除一些已经分配的资源(文件描述符、句柄等),不推荐在其中重启进程
unhandledRejection 事件
如果一个 Promise 回调的异常没有被.catch()捕获,那么就会触发 process 的 unhandledRejection 事件:
process.on("unhandledRejection", (err, promise) => {
console.log(err.message);
});
Promise.reject(new Error("错误信息")); // 未被catch捕获的异常,交由unhandledRejection事件处理
# 如何处理进程退出
一个 nodejs 进程,可以通过 process.exit() 来指定退出代码,直接退出。不推荐直接使用 process.exit(),这会导致事件循环中的任务直接不被处理,以及可能导致数据的截断和丢失(例如 stdout 的写入)
setTimeout(() => {
console.log("我不会执行");
});
process.exit(0);
正确安全的处理是,设置 process.exitCode,并允许进程自然退出。
setTimeout(() => {
console.log("我不会执行");
});
process.exitCode = 1;
beforeExit 事件
用于处理进程退出的事件有:beforeExit 事件 和 exit 事件。
当 Node.js 清空其事件循环并且没有其他工作要安排时,会触发 beforeExit 事件。例如在退出前需要一些异步操作,那么可以写在 beforeExit 事件中:
let hasSend = false;
process.on("beforeExit", () => {
if (hasSend) return; // 避免死循环
setTimeout(() => {
console.log("mock send data to serve");
hasSend = true;
}, 500);
});
console.log(".......");
// 输出:
// .......
// mock send data to serve
注意:在 beforeExit 事件中如果是异步任务,那么又会被添加到任务队列。此时,任务队列完成所有任务后,又回触发 beforeExit 事件。因此,不处理的话,可能出现死循环的情况。如果是显式调用 exit(),那么不会触发此事件。
exit 事件 在 exit 事件中,只能执行同步操作。在调用 'exit' 事件监听器之后,Node.js 进程将立即退出,从而导致在事件循环中仍排队的任何其他工作被放弃