4.4 Error Handling
Wow! We've covered quite a bit in this chapter.
The final topic to discuss is error handling.
While the previous control flow statements control how the program flows under normal circumstances, error handling statements control how the program flows when an error occurs.
Ready?
Let's proceed!
4.4.1 try… catch… finally
To deal with errors, we use the try… catch… finally statement. The syntax is as follows:
try {
Do something
} catch (err) {
Deal with any error that occurs
} finally {
Do something regardless of whether there’s an error or not
}
When we use the try…catch…finally statement, the program will first try to execute the statements in the try block. If an error occurs, it’ll be handled in the catch block. After processing the try and catch blocks, the program proceeds to the finally block and executes the statements inside regardless of whether an error has occurred.
Let’s look at an example to see how this works.
Add the following code to chap4.js.
display("My name is Jamie"); console.log("This statement will not be displayed");
What happens when you refresh the browser? You should see the following message displayed in the console.
Uncaught ReferenceError: display is not defined
This is because, in the first statement, we tried to use the display() method which does not exist. Hence, an error occurs. When that happens, the program “crashes” and anything after the error is not executed.
To prevent this from happening, we can write code to handle the error. Let’s see how we can handle the error above. Remove the previous two lines from chap4.js and add the following lines to it:
try { display("My name is Jamie"); } catch (err) { console.log(err.name + ": " + err.message); } finally { console.log("The finally block is always executed"); } console.log("Program proceeds after try...catch...finally block");
Now refresh your browser and observes what happens.
We get the following output in the console:
ReferenceError: display is not defined
The finally block is always executed
Program proceeds after try…catch…finally block
When the program tries to process the code in the try block, an error occurs because the display() method does not exist. This error is handled in the catch block.
The catch block catches an error called err, which is an object that belongs to the Error class. We’ll discuss objects and classes in Chapter 6.
The err object has two important properties called name and message that states the name of the error and explains the reason for it. To display these properties, we write
console.log(err.name + ": " + err.message);
This gives us the line
ReferenceError: display is not defined
in the output.
After the statement in the catch block is executed, the code in the finally block is executed. The finally block is optional and is always executed regardless of whether the try or catch block is executed.
This gives us the line
The finally block is always executed
in the output.
After the try…catch…finally statement is executed, the program went on to execute the last statement. This illustrates that the program does not crash after an error occurs, as long as the error is handled in the catch block.
4.4.2 Catching specific errors
In the previous example, we used the line
console.log(err.name + ": " + err.message);
to handle any error that occurs.
If you prefer, you can also choose to handle specific errors. This is useful if you want to perform different tasks depending on the error caught. For instance, you may want to display a different message for each error.
Javascript comes with 6 pre-defined types of errors.
SyntaxError
SyntaxError occurs when Javascript tries to interpret syntactically invalid code. However, this error is seldom thrown by the browser. An error has to be thrown by the browser before it can be 'caught' using the try…catch…finally statement.
The main syntax error that is thrown by the browser is error caused by the eval() function.
The eval() function is a built-in Javascript function that evaluates code represented as a string. For instance, eval('5*2') gives us 10 as the string '5*2' is evaluated to give us the product of 5 and 2.
If you use the eval() function wrongly, the browser will throw a SyntaxError.
Example:
eval('5 * ');
The statement above gives us a SyntaxError because the number after * is missing. Hence, eval() is unable to evaluate the product.
EvalError
The next error is EvalError.
This is for handling errors in the eval() function too. However, this error is no longer thrown by newer versions of Javascript. Other forms of errors (especially SyntaxError) are thrown instead.
RangeError
RangeError occurs when a number is out of its permitted range. An example is when we use the toFixed() method.
toFixed() is a built-in Javascript method that formats a number using fixed-point notation, rounding it off to a specified number of decimal places and returning it as a string. It takes in one argument from 1 to 20 inclusive (though some browsers may allow the argument to be up to 100).
For instance, if we write
var num = 1.23456;
console.log(num.toFixed(2));
we’ll get 1.23 as the output (rounded to 2 decimal places).
However, if we write
console.log(num.toFixed(101));
we’ll get a RangeError because toFixed() cannot accept 101 as an argument as 101 is out of its permitted range.
ReferenceError
ReferenceError occurs when you use a variable or method that does not exist.
For instance, if we write
console.log(x + y);
without first declaring x and y, we’ll get a ReferenceError.
TypeError
TypeError occurs when a value is not of the expected type. An example is when we use the toUpperCase() method.
toUpperCase() is a built-in Javascript method that converts a string to uppercase.
If we write
var num = 1.23456;
console.log(num.toUpperCase());
we’ll get a TypeError because you cannot convert a number to uppercase.
URIError
URIError occurs when we provide a deformed URI to one of the built-in URI handling functions. An example is the decodeURI() function. This function decodes a Uniform Resource Identifier (URI) by replacing escape sequences in the URI with their corresponding characters.
An example is the space character. When you type a space in your URI, this actually gets encoded as %20. You can try typing
http://www.example.com/hello world.html
into your browser address bar. You should see it encoded as
http://www.example.com/hello%20world.html
We can use the decodeURI() function to change %20 back to a space.
If you write
console.log(decodeURI('http://www.example.com/hello%20world.html'));
you’ll get
http://www.example.com/hello world.html
as the output.
However, if you write
console.log(decodeURI('http://www.example.com/hello%2world.html'));
you’ll get a URIError because decodeURI() is unable to decode %2.
Now that we’ve looked at the 6 pre-defined errors, let’s look at how we can catch them. To do that, we use the instanceof keyword. This allows us to narrow down the type of error caught and handle them accordingly. An example is shown below.
var num = 1.23456; try { //eval('5 * '); //console.log(num.toFixed(101)); //console.log(x + y); //console.log(num.toUpperCase()); //console.log(decodeURI('http://www.example.com/hello%2world.html')); } catch (err) { if (err instanceof SyntaxError) { console.log("Syntax Error"); } else if (err instanceof EvalError) { console.log("Eval Error"); } else if (err instanceof RangeError) { console.log("Range Error"); } else if (err instanceof ReferenceError) { console.log("Reference Error"); } else if (err instanceof TypeError) { console.log("Type Error"); } else if (err instanceof URIError) { console.log("URI Error"); } else console.log("Unknown Error"); }
Try uncommenting the statements in the try block one by one to test out each error. You’ll get a different message each time depending on the type of error caught.