错误处理——try…catch
无论我们编程多么精通,脚本错误怎是难免。可能是我们的错误造成,或异常输入,错误的服务器端响应以及无数个其他原因。
通常,当发送错误时脚本会立刻停止,打印至控制台。
但try…catch语法结构可以捕获错误并可以做更多的事情,而不是直接停止。
try…catch语法
try {
// code...
} catch (err) {
// error handling
}
工作流程如下:
1.首先try{…}代码块执行。
2.如果没有错误,那么catch(err)被忽略:执行到try结尾时,跳过catch块。
3.如果发生错误,那么try块中执行停止,控制流进入catch(err).err(可以是任何名称)变量包含错误发生相关的信息信息对象。
所以,try{…}块内的错误不会让脚本停止:我们有机会在catch块内处理。
无错误示例:显示alert (1) 和 (2):
try {
alert(‘Start of try runs’); // (1) <–
// …no errors here
alert(‘End of try runs’); // (2) <–
} catch(err) {
alert(‘Catch is ignored, because there are no errors’); // (3)
}
alert(“…Then the execution continues”);
带错误示例:显示 (1)和(3):
try {
alert(‘Start of try runs’); // (1) <–
lalala; // error, variable is not defined!
alert(‘End of try (never reached)’); // (2)
} catch(err) {
alert(Error has occured!); // (3) <–
}
alert(“…Then the execution continues”);
try…catch仅作用在运行时错误
对try…catch,代码必须是运行时,换句话说,必须是有效的Javascript代码。
如果代码语法错误不会工作
Throw操作
该操作产生一个错误。语法:
throw <error object>
技术上,可以使用任何内容作为错误对象。可以是原始类型,如数字或字符串,但最好使用对象,并带有name和message属性(与内置错误对象兼容)。
Javascript有很多内置标准错误构造器:Error、SyntaxError、ReferenceError、TypeError等其他。我们也能使用他创建错误对象。
语法:
let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...
对内置错误对象(仅为错误对象),name属性正好是构造函数的名称,message是构造函数参数。
let error = new Error("Things happen o_O");
alert(error.name); // Error
alert(error.message); // Things happen o_O
try…catch…finally
结构try…catch可以有多个代码子句:finally,如果存在,所有情况都会执行。
try之后,如果没有错误情况
catch之后,如果有错误
扩展语法类似如下:
try {
... try to execute the code ...
} catch(e) {
... handle errors ...
} finally {
... execute always ...
}
try {
alert( 'try' );
if (confirm('Make an error?')) BAD_CODE();
} catch (e) {
alert( 'catch' );
} finally {
alert( 'finally' );
}
代码有两条执行路径:
1.如果回答“Yes”产生一个错误,那么执行路径为try->catch->finally.
2.如果回调“No”,那么路径为try->finally.
子句finally通常应用场景为:在try…catch块之前开始做某事,无论结果如何都需要终止。
举例,我们想衡量斐波拉切函数fib(n)执行时间,很自然,我们需要在执行前和结束后衡量。但如果在函数调用期间有错误?特别是,下面代码中的fib(n)的实现将返回一个针对负数或非整数的错误。
不管发生什么,子句finally很适合去完成时间测量。
finally负责在两种场景下测试执行时间——成功执行fib函数和错误情况
在try…catch…finally块中的变量是局部变量
注意在上面代码result和diff变量,是在try…catch块之前声明的。
否则,如果使用let在{…}块里面,则只能在块内部可见。
总结
结构try...catch
可以处理运行时错误,字面理解为尝试运行代码,然后捕获可能发生的错误。
也可能没有catch或finally块,所以try...catch
和try...finally
都是有效语法。
错误对象有下面属性:
message
——用户可以理解的错误信息。
name
——错误名称字符串(错误构造函数名称)。
stack
——非标准——发生错误是的堆栈信息。
我们也能通过使用throw
操作生成自己的错误,技术上,throw的参数可以是任意类型,但通常是从内置错误类Error继承的对象。后面会介绍扩展错误对象。
再次抛出是错误处理的基本模式:catch
块通常期望并知道怎样处理特定的错误,所以应该重新抛出未知错误。
即使我们没有使用try…catch,大多数环境也支持设置全局的错误处理,捕获所有发生的错误,浏览器内置的是window.onerror.