首页 > 解决方案 > 即使处理了未捕获的异常,Node.js 程序也会退出

问题描述

我编写了以下代码来处理我的应用程序中的未捕获异常(我知道这是一种相当幼稚的错误处理方法,该代码仅用于问题的目的):

process.on("uncaughtException", err => {
    console.log('Handling exception');
});

console.log('starting...');

function f() {
    throw(new Error('Error'));
}

f();
console.log('Done');

当我运行代码时,我得到以下输出:

starting...
Handling exception

由于某种原因,即使处理了异常,程序也没有运行最后一行代码就退出了。f()当我用一个块包裹调用时try-catch,最后一行被执行并且“完成”这个词被打印到屏幕上。

我的问题是:

  1. 这是预期的行为吗?
  2. 为什么这两种机制(监听事件和使用try-catch)有区别?

标签: javascriptnode.jsexception

解决方案


这正是您所期望的行为,未捕获的异常将停止脚本的正常执行,因此永远不会进行“完成”日志调用。

您可以在此处的 Node.js 文档中看到更好的示例:https ://nodejs.org/api/process.html#process_event_uncaughtexception

正如文档所说:

请注意,“uncaughtException”是一种粗略的异常处理机制,仅用作最后的手段。

他们明确记录“这不会运行”,因为这是预期的行为。

如果您确实捕获了异常,脚本执行将不会停止,并且日志调用将照常进行。

process.on('uncaughtException', (err, origin) => {
  fs.writeSync(
    process.stderr.fd,
    `Caught exception: ${err}\n` +
    `Exception origin: ${origin}`
  );
});

setTimeout(() => {
  console.log('This will still run.');
}, 500);

// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
console.log('This will not run.');

uncaughtException 处理程序正是为了做到这一点:在您自己的代码中捕获任何未由 try ... catch 处理程序处理的异常。主要目的应该是记录错误,以便以后可以修复它们。

在任何情况下,最好将脚本包装在像 Forever 这样的重启机制中,或者如果发生这种情况,只需启动一个新的 Docker 容器。

现在在您的情况下没有真正的区别,因为脚本无论如何都会立即退出。但是看看这两个脚本之间的区别:

脚本 1:

// Keep the script alive by setting a timeout. Because we have an exception handler in place we can keep doing stuff!
let interval = setInterval(() => console.log("I'm still alive!!"), 500);
setTimeout(() => { clearInterval(interval); console.log("Timeout done...")} , 5000);

process.on("uncaughtException", err => {
    console.log('Handling exception');
});

console.log('starting...');

function f() {
    throw(new Error('Error'));
}

f();

console.log('Done');

脚本 2:

// Keep the script alive by setting a timeout. Since there is no exception handler set the script will terminate immediately in any case.

let interval = setInterval(() => console.log("I'm still alive!!"), 500);
setTimeout(() => { clearInterval(interval); console.log("Timeout done...")} , 5000);

console.log('starting...');

function f() {
    throw(new Error('Error'));
}

f();

console.log('Done');

您可以在第二个脚本中看到我们直接退出,因为我们没有未捕获的异常处理程序。


推荐阅读