简体   繁体   中英

Node.js program exits even though uncaught exceptions are handled

I wrote the following code for handling uncaught exceptions in my application (I know this is a rather naive error handling appraoch, the code is just for the purpose of the question):

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

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

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

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

When I ran the code, I got the following output:

starting...
Handling exception

For some reason, even though the exception was handled, the program exited without running the last line of code. When I wrapped the call to f() with a try-catch block, the last line executed and the word 'Done' was printed to the screen.

My questions are:

  1. Is this the expected behaviour?
  2. Why is there a difference between these two mechanisms (listening to the event and using try-catch)?

This is exactly the behaviour you would expect, the uncaught exception will stop normal execution of the script so the "Done" log call will never be made.

You can see an even better example of this in the Node.js docs here: https://nodejs.org/api/process.html#process_event_uncaughtexception

As the documentation says:

Note that 'uncaughtException' is a crude mechanism for exception handling intended to be used only as a last resort.

They explicitly log "This will not run" as this is the expected behaviour.

If you do catch the exception the script execution will not stop and the log call will be made as normal.

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.');

The uncaughtException handler is meant to do exactly that: Catch any exceptions not handled by try ... catch handlers in your own code. The main purpose should be to log an errors so they can be fixed later on.

In any case it's probably best to wrap the script in a restart mechanism like Forever or just spinning up a new Docker container if this happens.

Now in your case there's no real difference since the script will exit straightaway anyway. But look at the difference between these two scripts:

Script 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');

Script 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');

You can see in the second script we exit straightaway since we have no uncaught exception handler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM