You have a block of code that throws an exception. You have tried putting it inside a try..catch block, but it still does not get caught. You have been told the error is thrown asynchronously, but you are not sure what is exactly going on. You would like to understand why your code doesn't catch it.
What is asynchronous code
Throwing exception asynchronously
The following code reproduces the example.
Here a try.. catch block is used to wrap a call to setImmediate(). It is a function that operates asynchronously and schedules the argument callback to be called in the near future, as soon as other operations have finished. There are no other statements to execute, and the control is passed back to one level up — to the Node.js event loop.
Pseudocode of event loop
The event loop is an infinite while loop that is entered as the last thing when Node.js process is started. Its responsibility is to repeatedly take events and fire any listeners registered for them one at a time. Listeners are called sequentially - one at a time.
It can be described by combining two API functions in a while loop.
Here getNextEvent() returns the next event. If there are no events available, it will block until new events occur. The getListeners() function returns an array of listeners that were waiting for the given event.
Run in two passes
Let's go back to the example. We can see there's the initial user code that makes the setImmediate()-call. The anonymous function passed as argument is not executed at this point, and it is only merely passed as an argument like a number, or a string would be passed.
We can think the highlighted code is executed in one pass. After the pass has finished, the control is passed one level up. Then, after other operations have finished, the setImmediate() contract is fulfilled, and the following section is executed.
If we combine the highlights, we can see the entire file actually contains pieces that are executed at different times.
Visualize executed passes by including surrounding event loop code
Let's combine this with the event loop pseudocode. We will replace the listener calling in the pseudocode with the actual code that will be executed. The first pass looks like
And the second part, after the "immediately after other operations have finished" event has occurred, looks like
From the second part, it can be seen that the original catch block that was intended to be there is not present. When the code is executed asynchronously, the original synchronous catch block is not present. In this case, the exception will propagate all the way up to the Node.js internals and will cause the program to exit prematurely.
Catch block is not present when asynchronous callback is executed
An asynchronous exception is uncatchable because the intended catch block is not present when the asynchronous callback is executed. Instead, the exception will propagate all the way and terminate the program.