Description
The try
statement always starts with a try
block. Then, a catch
block, a finally
block, or both must be present. This gives us three forms for the try
statement:
try...catch
try...finally
try...catch...finally
Unlike other constructs such as if
or for
, the try
, catch
, and finally
blocks must be blocks, instead of single statements.
try doSomething(); // SyntaxError catch (e) console.log(e);
A catch
-block contains statements that specify what to do if an exception
is thrown in the try
-block. If any statement within the
try
-block (or in a function called from within the try
-block)
throws an exception, control is immediately shifted to the catch
-block. If
no exception is thrown in the try
-block, the catch
-block is
skipped.
The finally
block will always execute before control flow exits the try...catch...finally
construct. It always executes, regardless of whether an exception was thrown or caught.
You can nest one or more try
statements. If an inner try
statement does not have a catch
-block, the enclosing try
statement's catch
-block is used instead.
You can also use the try
statement to handle JavaScript exceptions. See
the JavaScript Guide for more information
on JavaScript exceptions.
Unconditional catch-block
When a catch
-block is used, the catch
-block is executed when
any exception is thrown from within the try
-block. For example, when the
exception occurs in the following code, control transfers to the
catch
-block.
try { throw 'myException'; // generates an exception } catch (e) { // statements to handle any exceptions logMyErrors(e); // pass exception object to error handler }
The catch
-block specifies an identifier (e
in the example
above) that holds the value of the exception; this value is only available in the
scope of the catch
-block.
Conditional catch-blocks
You can create "Conditional catch
-blocks" by combining
try...catch
blocks with if...else if...else
structures, like
this:
try { myroutine(); // may throw three types of exceptions } catch (e) { if (e instanceof TypeError) { // statements to handle TypeError exceptions } else if (e instanceof RangeError) { // statements to handle RangeError exceptions } else if (e instanceof EvalError) { // statements to handle EvalError exceptions } else { // statements to handle any unspecified exceptions logMyErrors(e); // pass exception object to error handler } }
A common use case for this is to only catch (and silence) a small subset of expected errors, and then re-throw the error in other cases:
try { myRoutine(); } catch (e) { if (e instanceof RangeError) { // statements to handle this very common expected error } else { throw e; // re-throw the error unchanged } }
The exception identifier
When an exception is thrown in the try
-block,
exception_var
(i.e., the e
in catch (e)
)
holds the exception value. You can use this identifier to get information about the
exception that was thrown. This identifier is only available in the
catch
-block's scope. If you don't need the
exception value, it could be omitted.
function isValidJSON(text) { try { JSON.parse(text); return true; } catch { return false; } }
The finally-block
The finally
block contains statements to execute after the try
block and catch
block(s) execute, but before the statements following the try...catch...finally
block. Control flow will always enter the finally
block, which can proceed in one of the following ways:
- Immediately before the
try
block finishes execution normally (and no exceptions were thrown); - Immediately before the
catch
block finishes execution normally; - Immediately before a control-flow statement (
return
,throw
,break
,continue
) is executed in thetry
block orcatch
block.
If an exception is thrown from the try
block, even when there's no catch
block to handle the exception, the finally
block still executes, in which case the exception is still thrown immediately after the finally
block finishes executing.
The following example shows one use case for the finally
-block. The code
opens a file and then executes statements that use the file; the
finally
-block makes sure the file always closes after it is used even if an
exception was thrown.
openMyFile(); try { // tie up a resource writeMyFile(theData); } finally { closeMyFile(); // always close the resource }
Control flow statements (return
, throw
, break
, continue
) in the finally
block will "mask" any completion value of the try
block or catch
block. In this example, the try
block tries to return 1, but before returning, the control flow is yielded to the finally
block first, so the finally
block's return value is returned instead.
function doIt() { try { return 1; } finally { return 2; } } doIt(); // returns 2
It is generally a bad idea to have control flow statements in the finally
block. Only use it for cleanup code.