JavaScript: The Definitive GuideJavaScript: The Definitive GuideSearch this book

6.17. try/catch/finally

The try/catch/finally statement is JavaScript's exception-handling mechanism. The try clause of this statement simply defines the block of code whose exceptions are to be handled. The try block is followed by a catch clause, which is a block of statements that are invoked when an exception occurs anywhere within the try block. The catch clause is followed by a finally block containing cleanup code that is guaranteed to be executed, regardless of what happens in the try block. Both the catch and finally blocks are optional, but a try block must be accompanied by at least one of these blocks. The try, catch, and finally blocks all begin and end with curly braces. These are a required part of the syntax and cannot be omitted, even if the clause contains only a single statement. Like the throw statement, the try/catch/finally statement is standardized by ECMAScript v3 and implemented in JavaScript 1.4.

The following code illustrates the syntax and purpose of the try/catch/finally statement. In particular, note that the catch keyword is followed by an identifier in parentheses. This identifier is like a function argument. It names a local variable that exists only within the body of the catch block. JavaScript assigns whatever exception object or value was thrown to this variable:

try {
  // Normally, this code runs from the top of the block to the bottom
  // without problems. But it can sometimes throw an exception,
  // either directly, with a throw statement, or indirectly, by calling
  // a method that throws an exception.
}
catch (e) {
  // The statements in this block are executed if, and only if, the try
  // block throws an exception. These statements can use the local variable
  // e to refer to the Error object or other value that was thrown.
  // This block may handle the exception somehow, or it may ignore the
  // exception by doing nothing, or it may rethrow the exception with throw.
}
finally {
  // This block contains statements that are always executed, regardless of
  // what happens in the try block. They are executed whether the try
  // block terminates:
  //   1) normally, after reaching the bottom of the block
  //   2) because of a break, continue, or return statement
  //   3) with an exception that is handled by a catch clause above
  //   4) with an uncaught exception that is still propagating
} 

Here is a more realistic example of the try/catch statement. It uses the factorial( ) method defined in the previous section and the client-side JavaScript methods prompt( ) and alert( ) for input and output:

try {
    // Ask the user to enter a number
    var n = prompt("Please enter a positive integer", "");
    // Compute the factorial of the number, assuming that the user's
    // input is valid
    var f = factorial(n);
    // Display the result
    alert(n + "! = " + f);
}
catch (ex) {  // If the user's input was not valid, we end up here
    // Tell the user what the error is
    alert(ex);
} 

This example is a try/catch statement with no finally clause. Although finally is not used as often as catch, it can often be useful. However, its behavior requires additional explanation. The finally clause is guaranteed to be executed if any portion of the try block is executed, regardless of how the code in the try block completes. It is generally used to clean up after the code in the try clause.

In the normal case, control reaches the end of the try block and then proceeds to the finally block, which performs any necessary cleanup. If control leaves the try block because of a return, continue, or break statement, the finally block is executed before control transfers to its new destination.

If an exception occurs in the try block and there is an associated catch block to handle the exception, control transfers first to the catch block and then to the finally block. If there is no local catch block to handle the exception, control transfers first to the finally block and then propagates up to the nearest containing catch clause that can handle the exception.

If a finally block itself transfers control with a return, continue, break, or throw statement, or by calling a method that throws an exception, the pending control transfer is abandoned and this new transfer is processed. For example, if a finally clause throws an exception, that exception replaces any exception that was in the process of being thrown. If a finally clause issues a return statement, the method returns normally, even if an exception has been thrown and has not yet been handled.

try and finally can be used together without a catch clause. In this case, the finally block is simply cleanup code that is guaranteed to be executed, regardless of any break, continue, or return statements within the try clause. For example, the following code uses a try/finally statement to ensure that a loop counter variable is incremented at the end of each iteration, even when an iteration terminates abruptly because of a continue statement:

var i = 0, total = 0;
while(i < a.length) {
    try {
        if ((typeof a[i] != "number") || isNaN(a[i])) // If it is not a number,
            continue;   // go on to the next iteration of the loop.
        total += a[i];  // Otherwise, add the number to the total.
    }
    finally {
        i++;  // Always increment i, even if we used continue above.
    }
} 



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.