try...catch

try...catch

try...catch语句将能引发错误的代码放在try块中,并且对应一个响应,然后有异常被抛出。

语法

try { try_statements } [catch (exception_var_1 if condition_1) { // non-standard catch_statements_1 }] ... [catch (exception_var_2) { catch_statements_2 }] [finally { finally_statements }]

try_statements需要被执行的语句。catch_statements_1,catch_statements_2如果在try块里有异常被抛出时执行的语句。exception_var_1,exception_var_2用于保存关联catch子句的异常对象的标识符。condition_1一个条件表达式。finally_statementstry语句块之后执行的语句块。无论是否有异常抛出或捕获这些语句都将执行。

描述

try语句包含了由一个或者多个语句组成的try块, 和至少一个catch子句或者一个finally子句的其中一个,或者两个兼有, 下面是三种形式的try声明:

  • try...catch

  • try...finally

  • try...catch...finally

catch子句包含try块中抛出异常时要执行的语句。也就是,你想让try语句中的内容成功, 如果没成功,你想控制接下来发生的事情,这时你可以在catch语句中实现。 如果有在try块中有任何一个语句(或者从try块中调用的函数)抛出异常,控制立即转向catch子句。如果在try块中没有异常抛出,会跳过catch子句。

finally子句在try块和catch块之后执行但是在下一个try声明之前执行。无论是否有异常抛出或着是否被捕获它总是执行。

你可以嵌套一个或者更多的try语句。如果内部的try语句没有catch子句,那么将会进入包裹它的try语句的catch子句。

你也可以用try语句去处理 JavaScript 异常。参考JavaScript 指南了解更多关于 Javascript 异常的信息。

无条件的catch子句

当使用单个无条件catch子句时,抛出的任何异常时都会进入到catch块。例如,当在下面的代码中发生异常时,控制转移到catch子句。

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

catch块指定一个标识符(在上面的示例中为e),该标识符保存由throw语句指定的值。catch块是唯一的,因为当输入catch块时,JavaScript 会创建此标识符,并将其添加到当前作用域;标识符仅在catch块执行时存在;catch块执行完成后,标识符不再可用。

条件catch子句

非标准

该特性是非标准的,请尽量不要在生产环境中使用它!

你也可以用一个或者更多条件catch子句来处理特定的异常。在这种情况下,当异常抛出时将会进入合适的catch子句中。在下面的代码中,try块的代码可能会抛出三种异常:TypeErrorRangeErrorEvalError。当一个异常抛出时,控制将会进入与其对应的catch语句。如果这个异常不是特定的,那么控制将转移到无条件catch子句。

当用一个无条件catch子句和一个或多个条件语句时,无条件catch子句必须放在最后。否则当到达条件语句之前所有的异常将会被非条件语句拦截。

提醒:这个功能不符合 ECMAscript 规范。

try { myroutine( // may throw three types of exceptions } catch (e if e instanceof TypeError) { // statements to handle TypeError exceptions } catch (e if e instanceof RangeError) { // statements to handle RangeError exceptions } catch (e if e instanceof EvalError) { // statements to handle EvalError exceptions } catch (e) { // statements to handle any unspecified exceptions logMyErrors(e // pass exception object to error handler }

下面用符合 ECMAscript 规范的简单的 JavaScript 来编写相同的“条件catch子句”(显然更加冗长的,但是可以在任何地方运行):

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 } }

异常标识符

try块中的抛出一个异常时, exception_var(如catch (e)中的e)用来保存被抛出声明指定的值。你可以用这个标识符来获取关于被抛出异常的信息。

这个标识符是catch子语句内部的。换言之,当进入catch子语句时标识符创建,catch子语句执行完毕后,这个标识符将不再可用。

finally子句

finally子句包含在try块和catch子句执行之后执行的语句,但在try..catch..finally块之后的语句之前。请注意,无论是否抛出异常finally子句都会执行。此外,如果抛出异常,即使没有catch子句处理异常,finally子句中的语句也会执行。当发生异常时,可以使用finally子句使您的脚本正常失败;例如,要进行一般的清理,您可能需要释放脚本绑定的资源。

有一个特殊的异常相关的子句可能会执行,无论是否有异常,但这个结构实际上是有用的。但重要的一点并不在于finally子句总是执行,而是普通的代码,是否遵循一个try..catch。例如,如果try的catch块中发生另一个异常,则包裹该try.catch的相同外部try块中的任何剩余代码(或在主流中,如果不在外部try块中)将不会得到因为控制立即转移到外部try的catch块(或内部的错误发生器,如果不在try块中)。因此,将退出之前在内部(或外部)中完成的任何常规清理代码将被跳过。然而,如果try块具有finally块,那么finally块代码将首先执行,以允许任何这样的清理,然后另一个try的catch-block(或者错误发生器)将被控制来处理第二例。现在,如果try..catch代码成功,则必须执行该例程清理,那么如果finally块仅在异常之后执行,则同样的清理代码必须在finally块的内部和外部都被复制,因此,没有理由只是一个独立的finally块,而是让它执行,不管是否有例外。

以下示例打开一个文件,然后执行使用该文件的语句(服务器端 JavaScript 允许您访问文件)。如果文件打开时抛出异常,则finally子句会在脚本失败之前关闭该文件。代码最终也会在trycatch块显式返回时执行。

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

示例

嵌套 try 块

首先让我们看看这里发生什么:

try { try { throw new Error('oops' } finally { console.log('finally' } } catch (ex) { console.error('outer', ex.message } // Output: // "finally" // "outer" "oops"

现在,如果我们已经捕获异常通过增加一个 catch 语句块

try { try { throw new Error('oops' } catch (ex) { console.error('inner', ex.message } finally { console.log('finally' } } catch (ex) { console.error('outer', ex.message } // Output: // "inner" "oops" // "finally"

现在,让我们再次抛出错误。

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 } // Output: // "inner" "oops" // "finally" // "outer" "oops"

任何给定的异常只会被离它最近的封闭 catch 块捕获一次。当然,在“inner”块抛出的任何新异常 (因为 catch 块里的代码也可以抛出异常),将会被“outer”块所捕获。

从 finally 语句块返回

如果从finally块中返回一个值,那么这个值将会成为整个try-catch-finally的返回值,无论是否有return语句在trycatch中。这包括在catch块里抛出的异常。

(function() { 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 } })( // Output: // "inner" "oops" // "finally"

因为 finally 块里的 return 语句,外部的“oops”异常没有抛出。从 catch 块返回的值同样适用。

规范

SpecificationStatusComment
ECMAScript 3rd Edition (ECMA-262)StandardInitial definition. Implemented in JavaScript 1.4
ECMAScript 5.1 (ECMA-262)The definition of 'try statement' in that specification.Standard
ECMAScript 2015 (6th Edition, ECMA-262)The definition of 'try statement' in that specification.Standard
ECMAScript Latest Draft (ECMA-262)The definition of 'try statement' in that specification.Living StandardNot part of the current ECMA-262 standard: Multiple catch clauses and conditional clauses (SpiderMonkey extension, JavaScript 1.5).

浏览器兼容性

FeatureChromeEdgeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support(Yes)(Yes)6 (6)(Yes)(Yes)(Yes)
Conditional clauses (non-standard)No supportNo support(Yes)No supportNo supportNo support

FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support(Yes)(Yes)(Yes)(Yes)(Yes)(Yes)(Yes)
Conditional clauses (non-standard)No supportNo support?(Yes)No supportNo supportNo support