What happens when an error occurs
When an error occurs in code, the engine creates an Error object, throws it and walks up the call stack looking for the nearest try...catch. If no handler is found, script execution stops; if one is found, the program continues from the line after the catch block.
Theory
TL;DR
- The engine (for example V8 in Chrome and Node.js) hits a situation it cannot handle.
- An error object with
name,messageandstackis created automatically. - The error is thrown and travels up the call stack.
- The engine looks for the nearest
try...catch; if the current function has none, the search continues in the calling function. - Without a handler the error bubbles all the way to the top and execution stops.
- With a caught error the program continues after the
catchblock, andfinallyruns in any case.
Quick example
function test() {
console.log(a); // ReferenceError
}
try {
test();
} catch (err) {
console.log("Error caught:", err.message);
}Here the error will not crash the program, because catch intercepted it.
Step 1: the engine detects the problem
While running the code the JavaScript engine hits a situation it cannot handle, for example:
console.log(a);The variable a is not defined. The engine sees that and creates an error object:
ReferenceError: a is not definedStep 2: an Error object is created
JavaScript automatically creates an object with information about the error:
{
name: "ReferenceError",
message: "a is not defined",
stack: "Stack trace..."
}It contains:
name, the error type;message, a text description;stack, the call stack, that is, where exactly the error happened.
Step 3: the error is thrown and looks for a handler
Once created, the engine throws this error up the call stack, meaning JavaScript looks for the nearest try...catch able to intercept it.
If the error happens inside a try block, JavaScript jumps straight to the matching catch. If the current function has no try...catch, the engine moves up the call stack, to the function that called the current one, and so on, until it finds a handler.
If no handler is found, the error bubbles all the way to the top and execution of the code stops.
Step 4: execution stops if the error is not caught
If the error is not caught, the program halts:
console.log(a);
console.log("This code will not run");After the ReferenceError on the first line execution is interrupted, and the second line is never executed.
Step 5: recovery and the finally block
If the error is caught in try...catch, the program continues after the catch block:
try {
JSON.parse("{ not valid json }");
} catch (error) {
console.log("An error occurred:", error.message);
}
console.log("The code continues...");The output:
An error occurred: Expected property name or '}' in JSON at position 2
The code continues...If you add a finally block, it always runs, no matter whether there was an error or not:
try {
throw new Error("Failure!");
} catch (e) {
console.log("Caught the error");
} finally {
console.log("This block runs in any case");
}That is exactly why finally is used for cleanup: close a connection, hide a loading indicator, release a resource.
The stages at a glance
| Stage | What happens |
|---|---|
| 1 | The problem is detected |
| 2 | An error object is created |
| 3 | The error is thrown |
| 4 | A handler (try...catch) is searched for |
| 5 | Execution is interrupted if the error is not caught |
| 6 | Work continues if the error was handled |
| 7 | The finally block runs, if there is one |
Common mistakes
- Thinking execution resumes at the point of failure after
catch. It does not: the lines intryafter the failing one are skipped for good, and the program continues from the code after the whole construct. - Expecting
try...catchto catch an asynchronous error. An exception insidesetTimeoutor in an unhandled promise happens on a later tick of the event loop, when the outertryhas already finished. - Ignoring
stack. The call stack is what shows the chain of functions that led to the failure; logging onlymessagethrows away the most useful part. - Putting a
returninsidefinally. That value overrides both the result oftryand the thrown error, so the failure simply disappears without a trace. - Assuming an uncaught error only breaks one line. It stops the entire current call stack, so nothing else in that branch of the code runs.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.