In this section, we will learn what the try catch blocks and exception handling are and how they work in JavaScript.
Error in JavaScript
While a JavaScript program is running (runtime), errors can occur. For example, let’s say our program takes an input from a user. The value is expected to be of type `Number` but somehow our program ends up getting a value of type String! In situations like this, the program might fail to progress properly or even worse, it might crash!
The default browser experience for JavaScript errors is horrible for the end users. In the best case, the user has no idea what happened and will try again; in the worst case, the user gets incredibly annoyed and never comes back.
Having a good error-handling strategy keeps our users informed about what is going on without scaring them.
Error Handling in JavaScript
As the name suggests, error handling means handling errors in a way so that they won’t crash our program!
Now, in order to do this, JavaScript provided a set of keywords that could be used to create statements that can control the areas where errors might occur and what should be done when those errors and exceptions occurred.
JavaScript try catch Statements
One of the ways in which we can trap and deal with JavaScript errors is via the `try catch` statement.
try catch Statements Syntax:
try { // Instructions that might throw an error } catch(error) { // Instructions to handle the error }
Any code that might possibly cause an error should be put in the `try` block.
Also, the code to handle the error is placed in the `catch` block.
Note: any `try` block is accompanied by at least one `catch` or `finally` block. In later sections, you’ll see what the `finally` block is.
If an error occurs at any point in the `try` block, the execution engine immediately exits and jumps into the `catch` block.
The `catch` block then receives an object containing information about the error that occurred.
We must define a name for the error object even if we don’t intend to use it. The exact information available on this object varies from browser to browser but contains, at a minimum, a `message` property that holds the error message.
Example: handling errors in JavaScript via try catch statements
console.log(a); console.log("End");
Output:
Uncaught ReferenceError: a is not defined
In this program, the execution engine tries to run the `console.log()` statement to send the value of the `a` variable to the browser’s console. But the problem is that there’s no variable with the name `a` in this program. So basically this is a reference error because this statement is referring to a variable that does not exist.
This is an error and by default if we don’t catch such an error, it will propagate and at the end crash the program.
That’s why the last statement didn’t get executed.
Example: JavaScript try-catch blocks
Now let’s refactor the program above and use the `try catch` statement to handle part of the program that might produce an error:
try{ console.log(a); }catch(error){ console.log("Inside the catch block"); console.log(error.name); console.log(error.message); } console.log("End");
Output:
Inside the catch block ReferenceError a is not defined End
Here, the first statement that the execution engine will run is the `console.log()` statement in the `try` block. There again because there’s no `a` variable in the program, the reference error occurrs. But this time, because there’s a catch block (the handler) is defined, the execution engine will jump from the `try` block into the `catch` block.
Note that the information about the error is passed as the argument to the `catch` statement.
In the body of the `catch` statement, first the message `Inside the catch block` will be sent to the browser’s console. After that, we used the `error` object to send the name as well as the message of the occurred error to the browser’s console.
Note: After the execution of the `catch` block is done, the execution engine will move to the instructions after this block. This means there’s no returning back to the `try` block.
For this reason, after the `catch` block, the execution engine ran the `console.log(“End”);` statement.
Example: try-catch block in JavaScript Error Handling
const res = true; try{ console.log(res()); }catch(error){ console.log("Inside the catch block"); console.log(error.name); console.log(error.message); } console.log("End");
Output:
Inside the catch block TypeError res is not a function End
This time in the `try` block, we called the `res` identifier as if it was a function. But in fact this identifier is not a function and so calling it as a function will produce the `TypeError` exception.
So now, after calling the `res` variable and causing an error, the execution engine moves from the `try` block into the `catch` block to handle the raised error.
Inside this block, again we send the message `Inside the catch block` as well as the name of the error and its message to the browser’s console.
At the end, the execution engine moved to the instructions after the body of the `catch` block and sends the message `End` to the browser’s console.
Note: The execution engine doesn’t care how you handle a raised error in the body of a catch block! All it cares is that it must find a handler and run its instructions! After that, from the execution-engine standpoint, the handler ran and theoretically, the error is handled now!
JavaScript Error Handling and Scope
When an error occurs in a scope, the execution engine first looks for a catch handler in that scope. But if it can’t find one, it will propagate the error back to the enclosing scope where the call occurred until:
- Either one of the scopes in the Stack has a handler and will handle the error.
- If there’s no handler in any of the scopes present in the Stack, the execution engine will throw the error to the browser’s console and terminate the program immediately.
Example: Scopes in JavaScript and Error Handling
function func(){ const res = true; res(); console.log("This messsage will never appear on the console"); } try{ func(); }catch(error){ console.log("Inside the catch block"); console.log(error.name); console.log(error.message); } console.log("End");
Output:
Inside the catch block TypeError res is not a function End
Here in the `try` block we first called the `func()` function. Inside the body of this function there’s call to the `res` identifier as if it is a function (which is not). So an error occurs here. But in this function there’s no catch handler to handle the produced error. So the execution engine jumps back to the enclosing scope (which in this case it is the global scope) right where the call to the `func()` function occurred. There, it will check to see if there’s a `catch` block to handle this error.
So because there’s one, the engine will invoke this body and run its instructions.
Again, after running the instructions of the `catch` block, the engine will move to the tasks after this block and will never return to where the error occurred.
JavaScript ReferenceError
The ReferenceError is thrown when we invoke a variable or the name of a function that does not exist!
Example: throwing ReferenceError in JavaScript
console.log(noVariable);
More to Read: