When there is a good chance that a program segment may cause an error, you may want to enclose the segment in a try-catch block. A try-catch block will try to execute all code between the curly braces. If an error is caused by the code in the block, the try-catch block will catch the error and allow you to either elegantly report the error to the user or totally suppress it.
Here is the try-catch block syntax:
try{ <statements> } catch( <identifier> ){ <statements> }
Statements in the try block will execute sequentially, just as usual. As soon as an error is generated, execution is rerouted to the catch block, where the error will be handled. After the catch block is executed, execution continues with the statement immediately after the catch block. Here is some pseudo code to demonstrate:
try { no error. no error. an error! control is passed to the catch block here. this will never execute. } catch( exception ) { error handling code is run here. } execution continues from here.
In general, it is not a good idea to let the visitor know when an error occurs—nobody wants to visit a Web site that generates errors. By using try-catch blocks, you can ensure that your Web site visitors never know when an error occurs.
<html> <head> <title> JavaScript Professional Projects - Handling Errors </title> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 13: Handling Errors</font> </center> <br><br> <br><br> This page contains a JavaScript error which is caught by a try-catch block. <script language="JavaScript"> <!-- try { document.write( myObject.toString() ); } catch( e ) { } // --> </script> </body> </html>
This example suppresses the example error used previously in the chapter. Try-catch blocks are also very useful when debugging your Web page and keeping it running.
The following example provides no error checking in the average() function:
<html> <head> <title> JavaScript Professional Projects - Handling Errors </title> <script language="JavaScript"> <!-- var theArray = new Array( 10, 99, 75, 42, 56, 2, 87, 15 ); function displayArray( a ) { for( i = 0 ; i < a.length ; i++ ) { document.write( "<b>" + a[i] + "</b>" ); if( i != a.length 1 ) document.write( ", " ); } } function average( a ) { var total = 0; for( i = 0 ; i < a.length ; i++ ) { total += a[i]; } return( total / a.length ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 13: Handling Errors</font> </center> <br><br> <br><br> The average of the array <script language="JavaScript"> <!-- displayArray( theArray ); // --> </script> is<b> <script language="JavaScript"> <!-- document.write( average( theArray ) ); // --> </script></b>. </body> </html>
At first glance, this situation might not seem like such a bad thing, but think about what would happen if an array of strings were passed to the function instead of an array of numbers. The average() function will return the value NaN, which is not helpful at all if you need to know the average of the array. The same is true if the array length is zero (a much more likely occurrence). Thankfully, there is a way to handle both these possibilities. Here is a modified version of the previous example:
<html> <head> <title> JavaScript Professional Projects - Handling Errors </title> <script language="JavaScript"> <!-- var theArray = new Array( 10, 99, 75, 42, 56, 2, 87, 15 ); function displayArray( a ) { for( i = 0 ; i < a.length ; i++ ) { document.write( "<b>" + a[i] + "</b>" ); if( i != a.length 1 ) document.write( ", " ); } } function average( a ) { if( a.length == 0 ) throw( "Divide by zero error." ); var total = 0; for( i = 0 ; i < a.length ; i++ ) { if( isNaN( a[i] ) ) throw( "Number array expected." ); total += a[i]; } return( total / a.length ); } // --> </script> </head> <body> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 13: Handling Errors</font> </center> <br><br> <br><br> The average of the array <script language="JavaScript"> <!-- displayArray( theArray ); // --> </script> is<b> <script language="JavaScript"> <!-- try { document.write( average( theArray ) ); } catch( e ) { document.write( "ERROR: " + e ); } // --> </script></b>. </body> </html>
The modified average() function checks that two conditions exist before it calculates the average of the array. The first condition is that the array has some elements in it. If the array is empty, a new exception is thrown with the error message "Divide by zero error." I chose this error message because the last line of the function divides total by the length of the array and an empty array has a length of zero. The second condition the function requires before it will calculate the average is that each element in the array be a number. This condition is checked during each iteration of the for loop. If an element is not a number, a "Number array expected" error message is thrown.
Creating and throwing errors is only half of what you need to do to keep errors from reaching the client. Each time you use the average() function you must put it in a try-catch block to catch the possible errors. In the previous example, the function call was placed in the following try-catch block, like this:
try { document.write( average( theArray ) ); } catch( e ) { document.write( "ERROR: " + e ); }
This try-catch block catches any of the errors that may or may not be created by the average() function. If no error is created—a non-zero length array of numbers is used—the program will return the average of the array and then print it to the screen. If an error is created, the try-catch block captures it and echoes it to the screen instead of the results of the average() function.
If you don't want to put the function call inside of a try-catch block each time you use it, you could alternatively write the average() function as follows:
function average( a ) { var total = 0; try { if( a.length == 0 ) throw( "Divide by zero error." ); for( i = 0 ; i < a.length ; i++ ) { if( isNaN( a[i] ) ) throw( "Number array expected." ); total += a[i]; } } catch( e ) { return( e ); } return( total / a.length ); }
This version of the function performs exactly like the previous one, except that you no longer have to place the function call in a try-catch block. The only disadvantage of this method is that you can no longer control what happens when an error occurs in the average() function because it is coded into the function itself.