i have a node.js server that i want to be able to handle exceptions without crashing, and i've got code kinda like the below. What i'm wanting to know, with all the event-driven awesomeness and callbacks and lambdas and all that, will my exceptions still be caught by my main entry point?
try {
http.get(..., function(results) {
// Might get an exception here
results.on('data', function () {
// Might also get an exception here
});
results.on('end', function () {
// Might also get an exception here
});
});
} catch(e) {
// Will the exceptions from the lambdas be caught here?
console.log('Nicely caught error: (' + e.name + '): ' + e.message);
}
Thanks
i have a node.js server that i want to be able to handle exceptions without crashing, and i've got code kinda like the below. What i'm wanting to know, with all the event-driven awesomeness and callbacks and lambdas and all that, will my exceptions still be caught by my main entry point?
try {
http.get(..., function(results) {
// Might get an exception here
results.on('data', function () {
// Might also get an exception here
});
results.on('end', function () {
// Might also get an exception here
});
});
} catch(e) {
// Will the exceptions from the lambdas be caught here?
console.log('Nicely caught error: (' + e.name + '): ' + e.message);
}
Thanks
Share Improve this question asked Feb 22, 2011 at 21:47 ChrisChris 40.7k46 gold badges195 silver badges239 bronze badges 1- Interesting: debuggable./posts/… – Chris Commented Feb 22, 2011 at 22:01
3 Answers
Reset to default 8It depends on the flow of control. Node.js puts emphasis on being asynchronous and one of the main drawbacks of asynchronicity is that the code doesn't flow in a way that you might be used to with a synchronized language.
In a synchronous language the caller is blocked while a function is waiting for some data. This makes the programmers job fairly simple because they can be guaranteed that when the function that's waiting for data returns, there will be data for the caller to consume.
It's the exact opposite in an asynchronous language, or with non-blocking I/O. In this case, the caller is blocked for the duration of the function call, however functions don't have to wait for data or I/O to plete before returning. This makes things slightly harder on the programmer because when an function call returns there are no guarantees about whether there will be data available. Hence, non-blocking I/O typically implies callback functions that get called when data is available to act on.
try/catch
blocks work with the call stack. That is, when an exception is thrown the runtime will unwind the call stack until it finds a catch
block that surrounds the call that threw the exception. But, since http.get
is a non-blocking call it exits immediately after registering some callbacks and processing continues. The callbacks are called in a separate "thread" and therefore the calls aren't nested within the original try/catch
block.
A diagram would really help explain things here but unfortunately I don't have one available to me.
The error handling style for the node.js standard library is to call the same callback, but pass a non-null first argument representing the error. If you have exceptional conditions in your asynchronous code, keep it in that format.
A throw would climb up the caller chain, which normally isn't aware of what callbacks are doing (for example, the tcp layer doesn't care that its data is parsed as http). Throwable exceptions are a bad fit for asynchronous programming.
In your example code, none of the potential exceptions thrown from within the http.get callback will land in your catch block. The stack of the callback is built from node's event loop when data is available to read.
There is a way to catch uncaught exceptions in node:
process.on("uncaughtException", function (err) {
console.log("uncaught exception: " + err);
});
This will sort of work for your example, depending on where the exception is.
The trouble is, uncaught exceptions can unravel node's inner workings in surprising ways, so you really don't want to depend on this. The only reliable way to catch all possible exceptions in a way that you can deal with them is to put a try/catch around every entry point from the event loop.
This sounds pretty tedious, but it usually isn't that bad. In your example program you are using node's API for HTTP requests, which is still a very low-level interface. For most things, you'd want to wrap up this exception catching functionality once and use it as a library.