JavaScript中try{}catch{}finally的使用

try{}catch{}finally{}的使用

try{}catch{}finally{} 语句一般是用来将有可能引发错误的代码(比如异步请求)放在try语句块中,并且对应一个响应,然后有异常被抛出到catch中。

语法:

try {
	//有可能引发错误的代码
} [catch (exception_var_1 if condition_1) {
	//处理错误为condition_1的情况
}] [catch (exception_var_2) {
	//处理其他的错误
}] [finally {
	//在try语句块之后执行的语句块。无论是否有异常抛出或捕获这些语句都将执行。
}]

描述:

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子句。

catch详细讲解:
无条件的catch子句

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

try {
	throw 'myError';
} catch (e) {
	console.error(e)
}

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

条件catch子句:

该特性是非标准的,请谨慎使用!

你也可以用一个或者更多条件catch子句来处理特定的异常。在这种情况下,当异常抛出时将会进入合适的catch子句中。在下面的代码中,try块的代码可能会抛出三种异常:TypeError,RangeError()和EvalError。当一个异常抛出时,控制将会进入与其对应的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
    console.error(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
       console.error(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-block中发生另一个异常,则包裹该try…catch的外部try-block中的剩余代码(或在主流中,如果不在外部try-block中)将不会执行,因为控制流会立即跳转到外部try的catch-block(或内部的错误发生器,如果不在try-block中)。
  • 因此,外部的包裹try-block(或主流)退出之前完成常规清理的代码将被跳过。然而,如果try-block有一个finally-block,那么finally-block代码将可以先来执行这些清理,然后另一个try的catch-block(或者错误发生器)再来处理第二个异常。
  • 现在,如果无论try…catch代码执行成功与否,清理例程都必须执行,并且finally-block只在发生异常时才执行,那么finally-block内部和外部需要多复制一份同样的清理例程,所以没有理由不只保留一个finally-block,并且不管是否有异常,都让它执行。
  • 以下示例打开一个文件,然后执行使用该文件的语句(服务器端 JavaScript 允许您访问文件)。如果文件打开时抛出异常,则finally子句会在脚本失败之前关闭该文件。finally中的代码最终也会在try或catch block显式返回时执行。
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"

现在,如果我们已经在 try 语句中,通过增加一个 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语句在try和catch中。这包括在catch块里抛出的异常。

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

// 注: 此 try catch 语句需要在 function 中运行才能作为函数的返回值, 否则直接运行会报语法错误
// Output:
// "inner" "oops"
// "finally"

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值