try...catch

try...catch 语句由 try 块和 catch 块、finally 块或两者组成。首先执行 try 块中的代码,如果抛出异常,则会执行 catch 块中的代码。finally 块中的代码将始终在控制流退出整个构造之前执行。

¥The try...catch statement is comprised of a try block and either a catch block, a finally block, or both. The code in the try block is executed first, and if it throws an exception, the code in the catch block will be executed. The code in the finally block will always be executed before control flow exits the entire construct.

Try it

语法

¥Syntax

js
try {
  tryStatements
} catch (exceptionVar) {
  catchStatements
} finally {
  finallyStatements
}
tryStatements

要执行的语句。

catchStatements

如果 try 块中抛出异常则执行的语句。

exceptionVar Optional

可选的 标识符或模式,用于保存关联 catch 块的已捕获异常。如果 catch 块不使用异常值,则可以省略 exceptionVar 及其周围的括号。

finallyStatements

在控制流退出 try...catch...finally 构造之前执行的语句。无论是否引发或捕获异常,这些语句都会执行。

描述

¥Description

try 语句始终以 try 块开头。然后,必须存在 catch 块或 finally 块。也可以同时拥有 catchfinally 块。这为我们提供了 try 语句的三种形式:

¥The try statement always starts with a try block. Then, a catch block or a finally block must be present. It's also possible to have both catch and finally blocks. This gives us three forms for the try statement:

  • try...catch
  • try...finally
  • try...catch...finally

iffor 等其他结构不同,trycatchfinally 块必须是块,而不是单个语句。

¥Unlike other constructs such as if or for, the try, catch, and finally blocks must be blocks, instead of single statements.

js
try doSomething(); // SyntaxError
catch (e) console.log(e);

catch 块包含指定在 try 块中引发异常时要执行的操作的语句。如果 try 块内(或从 try 块内调用的函数)中的任何语句引发异常,则控制立即转移到 catch 块。如果 try 块中没有抛出异常,则跳过 catch 块。

¥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.

finally 块将始终在控制流退出 try...catch...finally 构造之前执行。无论是否抛出或捕获异常,它总是执行。

¥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.

你可以嵌套一个或多个 try 语句。如果内部 try 语句没有 catch 块,则使用封闭的 try 语句的 catch 块。

¥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.

你还可以使用 try 语句来处理 JavaScript 异常。有关 JavaScript 异常的更多信息,请参阅 JavaScript 指南

¥You can also use the try statement to handle JavaScript exceptions. See the JavaScript Guide for more information on JavaScript exceptions.

捕捉绑定

¥Catch binding

try 块中抛出异常时,exceptionVar(即 catch (e) 中的 e)保存异常值。你可以使用此 binding 来获取有关引发的异常的信息。此 binding 仅在 catch 块的 scope 中可用。

¥When an exception is thrown in the try block, exceptionVar (i.e., the e in catch (e)) holds the exception value. You can use this binding to get information about the exception that was thrown. This binding is only available in the catch block's scope.

它不需要是单个标识符。你可以使用 解构模式 一次分配多个标识符。

¥It doesn't need to be a single identifier. You can use a destructuring pattern to assign multiple identifiers at once.

js
try {
  throw new TypeError("oops");
} catch ({ name, message }) {
  console.log(name); // "TypeError"
  console.log(message); // "oops"
}

catch 子句创建的绑定与 catch 块位于同一范围内,因此 catch 块中声明的任何变量不能与 catch 子句创建的绑定具有相同的名称。(有 此规则的一个例外,但它是已弃用的语法。)

¥The bindings created by the catch clause live in the same scope as the catch block, so any variables declared in the catch block cannot have the same name as the bindings created by the catch clause. (There's one exception to this rule, but it's a deprecated syntax.)

js
try {
  throw new TypeError("oops");
} catch ({ name, message }) {
  var name; // SyntaxError: Identifier 'name' has already been declared
  let message; // SyntaxError: Identifier 'message' has already been declared
}

异常绑定是可写的。例如,你可能想要规范化异常值以确保它是 Error 对象。

¥The exception binding is writable. For example, you may want to normalize the exception value to make sure it's an Error object.

js
try {
  throw "Oops; this is not an Error object";
} catch (e) {
  if (!(e instanceof Error)) {
    e = new Error(e);
  }
  console.error(e.message);
}

如果不需要异常值,可以将其与括号一起省略。

¥If you don't need the exception value, you can omit it along with the enclosing parentheses.

js
function isValidJSON(text) {
  try {
    JSON.parse(text);
    return true;
  } catch {
    return false;
  }
}

最后块

¥The finally block

finally 块包含在 try 块和 catch 块执行之后、但在 try...catch...finally 块后面的语句之前执行的语句。控制流将始终进入 finally 块,可以通过以下方式之一进行:

¥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:

  • try 块正常执行完成后(并且没有抛出异常);
  • catch 块正常执行完毕后立即;
  • 紧接在 try 块或 catch 块中执行控制流语句(returnthrowbreakcontinue)之前。

如果从 try 块抛出异常,即使没有 catch 块来处理异常,finally 块仍然会执行,在这种情况下,在 finally 块执行完成后仍然会立即抛出异常。

¥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.

以下示例显示了 finally 块的一个用例。代码打开一个文件,然后执行使用该文件的语句;finally 块确保文件在使用后始终关闭,即使抛出异常也是如此。

¥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.

js
openMyFile();
try {
  // tie up a resource
  writeMyFile(theData);
} finally {
  closeMyFile(); // always close the resource
}

finally 块中的控制流语句(returnthrowbreakcontinue)将 "mask" try 块或 catch 块的任何完成值。在此示例中,try 块尝试返回 1,但在返回之前,控制流首先让位于 finally 块,因此改为返回 finally 块的返回值。

¥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.

js
function doIt() {
  try {
    return 1;
  } finally {
    return 2;
  }
}

doIt(); // returns 2

finally 块中包含控制流语句通常是一个坏主意。仅将其用于清理代码。

¥It is generally a bad idea to have control flow statements in the finally block. Only use it for cleanup code.

示例

¥Examples

无条件 catch 块

¥Unconditional catch block

使用 catch 块时,当 try 块内抛出任何异常时,将执行 catch 块。例如,当以下代码中发生异常时,控制权将转移到 catch 块。

¥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.

js
try {
  throw "myException"; // generates an exception
} catch (e) {
  // statements to handle any exceptions
  logMyErrors(e); // pass exception object to error handler
}

catch 块指定一个保存异常值的标识符(上例中的 e);该值仅在 catch 块的 scope 中可用。

¥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.

条件 catch 块

¥Conditional catch blocks

你可以通过将 try...catch 块与 if...else if...else 结构组合来创建“条件 catch 块”,如下所示:

¥You can create "Conditional catch blocks" by combining try...catch blocks with if...else if...else structures, like this:

js
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:

js
try {
  myRoutine();
} catch (e) {
  if (e instanceof RangeError) {
    // statements to handle this very common expected error
  } else {
    throw e; // re-throw the error unchanged
  }
}

这可能会模仿其他语言的语法,例如 Java:

¥This may mimic the syntax from other languages, like Java:

java
try {
  myRoutine();
} catch (RangeError e) {
  // statements to handle this very common expected error
}
// Other errors are implicitly re-thrown

嵌套的 try 块

¥Nested try blocks

首先,让我们看看会发生什么:

¥First, let's see what happens with this:

js
try {
  try {
    throw new Error("oops");
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("outer", ex.message);
}

// Logs:
// "finally"
// "outer" "oops"

现在,如果我们已经通过添加 catch 块捕获了内部 try 块中的异常:

¥Now, if we already caught the exception in the inner try block by adding a catch block:

js
try {
  try {
    throw new Error("oops");
  } catch (ex) {
    console.error("inner", ex.message);
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("outer", ex.message);
}

// Logs:
// "inner" "oops"
// "finally"

现在,让我们重新抛出该错误。

¥And now, let's rethrow the error.

js
try {
  try {
    throw new Error("oops");
  } catch (ex) {
    console.error("inner", ex.message);
    throw ex;
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("outer", ex.message);
}

// Logs:
// "inner" "oops"
// "finally"
// "outer" "oops"

任何给定的异常只会被最近的封闭 catch 块捕获一次,除非重新抛出。当然,在 "inner" 块中引发的任何新异常(因为 catch 块中的代码可能会执行抛出的操作),都将被 "outer" 块捕获。

¥Any given exception will be caught only once by the nearest enclosing catch block unless it is rethrown. Of course, any new exceptions raised in the "inner" block (because the code in catch block may do something that throws), will be caught by the "outer" block.

从 finally 块返回

¥Returning from a finally block

如果 finally 块返回一个值,则该值将成为整个 try-catch-finally 语句的返回值,无论 trycatch 块中的任何 return 语句如何。这包括 catch 块内部引发的异常:

¥If the finally block returns a value, this value becomes the return value of the entire try-catch-finally statement, regardless of any return statements in the try and catch blocks. This includes exceptions thrown inside of the catch block:

js
(() => {
  try {
    try {
      throw new Error("oops");
    } catch (ex) {
      console.error("inner", ex.message);
      throw ex;
    } finally {
      console.log("finally");
      return;
    }
  } catch (ex) {
    console.error("outer", ex.message);
  }
})();

// Logs:
// "inner" "oops"
// "finally"

由于在 finally 块中返回,因此不会抛出外部 "oops"。这同样适用于从 catch 块返回的任何值。

¥The outer "oops" is not thrown because of the return in the finally block. The same would apply to any value returned from the catch block.

规范

Specification
ECMAScript Language Specification
# sec-try-statement

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看

¥See also