Today I learned: How to use throw and try/catch blocks in combination with setTimeout
Posted on
The problem
You should beware when using setTimeout together with throw and
try/catch block.
At first sight you may think that the below code is just fine and that it will fail gracefully and proceed with the fallback plan.
Well, not quite.
function willErrorBeCaught() {
try {
setTimeout(function callbackFunction() {
throw new Error('There was a problem');
}, 3000);
} catch (error) {
console.warn('There was a problem');
// Placeholder for fallback implementation
}
}
willErrorBeCaught();
The above code produces an "Uncaught Error: There was a problem".
The reason is that, by the time the callbackFunction function is executed,
i.e. after at least 3 seconds, the willErrorBeCaught function will have
already been removed from the call stack. This makes its catch block code
unreachable, and thus, the error uncaught.
This is indeed stated in the MDN docs:
Execution of the current function will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack. If no catch block exists among caller functions, the program will terminate.
The solution
The solution is rather simple. Shift the try/catch block into the
callbackFunction function, as show in the code snippet below.
function willErrorBeCaught() {
setTimeout(function callbackFunction() {
try {
throw new Error('There was a problem');
} catch (error) {
console.warn('There was a problem');
// Placeholder for fallback implementation
}
}, 3000);
}
willErrorBeCaught();
Now upon throw the "control will be passed to the first catch block in the
call stack" which is the one from the currently executed function, i.e.
callbackFunction.