js:try…catch…finally捕获错误处理的用法实例
我们在JS编程时,特别在调试阶段,捕获错误是非常有必要的,这将大大提高我们的勘错效率。而要把程序编写得更安全坚固,错误处理也必不可少。
JS存在一种语法构造try…catch,该语法构造使我们可以“捕获”错误,这使脚本可以执行得更加合理而不会因遇到“死亡脚本”导致程序执行失败。
js: try-catch-finally捕获错误
“ try…catch”语法
该try…catch构造有两个主要块:try
和catch
:
try {
// 代码…
} catch (err) {
// 错误处理
}
它是这样的:
首先,执行try {...}
中的代码。
如果没有错误,则将忽略catch(err)
:执行到达try
的结尾并继续,跳过catch
。
如果发生错误,则try
执行将停止,控制流向catch(err)
的开头。该err
变量(我们可以使用它的任何名称)将包含发生了什么详细的错误对象。
因此,try {...}
块内的错误不会杀死脚本,我们有机会在catch
中处理它。
让我们看一些例子。
一个无错误的示例:显示(1)和(2):
try {
alert(‘开始运行try’); // (1) <–
// …这里无错误
alert(‘结束运行try’); // (2) <–
} catch (err) {
alert(‘catch被忽略,因为这里无错误’); // (3)
}
trying >>
带有错误的示例:显示(1)和(3):
try {
alert(‘开始运行try’); // (1) <–
lalala; // 错误,变量未定义!
alert(‘结束运行try(永远不会到达)’); // (2)
} catch (err) {
alert(‘出现错误!’); // (3) <–
}
trying >>
try…catch 仅适用于运行时错误
为了try…catch工作,代码必须是可运行的。换句话说,它应该是有效的JavaScript。
如果代码在语法上是错误的,那么它将无法正常工作,例如,它具有不匹配的花括号:
try {
{{{{{{{{{{{{
} catch (err) {
alert(“引擎不懂这个代码,无效代码”);
}
trying >>
JavaScript引擎首先读取代码,然后运行它。在读取阶段发生的错误称为“解析时”错误,并且无法恢复(从该代码内部),那是因为引擎无法理解代码。
因此,try…catch只能处理有效代码中发生的错误。这种错误称为“运行时错误”,有时也称为“异常”。
try…catch 同步工作
如果在“预定的”代码中发生异常,例如在try
中setTimeout
,则try…catch不会捕获到该异常:
try {
setTimeout(function() {
noSuchVariable; // 脚本在这里停止
}, 1000);
} catch (err) {
alert( “不会执行” );
}
trying >>
这是因为函数本身是在引擎已离开try…catch构造时稍后执行的。
要在预定函数内捕获异常,try…catch必须在该函数内:
setTimeout(function() {
try {
noSuchVariable; // try…catch 处理这个错误!
} catch {
alert( “错误被捕获!” );
}
}, 1000);
trying >>
try…catch…finally
try…catch构造可能还包含一个代码子句:finally
。
如果存在,它将在所有情况下运行:
- try之后,如果没有错误,
- catch之后,如果有错误。
扩展语法如下所示:
try {
… 尝试执行这里代码 …
} catch (err) {
… 处理错误 …
} finally {
… 总是执行 …
}
try…catch…finally执行流程
尝试运行以下代码:
try {
alert( ‘try’ );
if (confirm(‘出错?’)) BAD_CODE();
} catch (err) {
alert( ‘catch’ );
} finally {
alert( ‘finally’ );
}
trying >>
该代码有两种执行方式:
- 如果你对“出错?”回答“是”,则try -> catch -> finally。
- 如果您说“否”,则try -> finally。
finally 和 return
该finally
子句适用于try…catch的任何退出,这里包括一个显式的return
。
在下面的示例中,有一个returnin try。在这种情况下,finally
在控件返回外部代码之前执行。
function func() {
try {
return 1;
} catch (err) {
/* … */
} finally {
alert( ‘finally’ );
}
}
alert( func() ); // 首先执行finally里的alert, 然后再执行try
trying >>
try…finally
try…finally不带catch
子句的构造也很有用。当我们不想在这里处理错误时,我们可以应用它,但是要确保我们启动的过程已经完成。
function func() {
// 开始做一些需要完成的事情
try {
// …
} finally {
// 即使全部死亡都完成那件事
}
}
try…catch有无finally的区别
比较两个代码片段。
1、第一个用于finally
执行以下代码try…catch:
try {
// 工作 工作
} catch (err) {
// 处理错误
} finally {
清洗工作空间
}
2、第二个片段把清洗空间放在try…catch的后面:
try {
// 工作 工作
} catch (err) {
// 处理错误
}
清洗工作空间
我们肯定需要在工作后进行清理,无论是否有错误都没有关系。
两个代码片段是否相等?在这里使用finally
是否有优势?下面两个例子说明了使用finally
的优势。
当我们看一个函数内部的代码时,区别变得很明显。
如果“跳出”,则try…catch的行为会有所不同。
例如,当有一个return
在try…catch内部时,该finally
在任何来自try…catch的出口工作,甚至是通过return
声明。catch
将在执行完finally
代码之后再执行。
function f() {
try {
alert(‘开始’);
return “结果”;
} catch (err) {
/// …
} finally {
alert(‘清洗!’);
}
}
f(); // 清洗!
trying >>
又例如,当函数内有throw
时:
function f() {
try {
alert(‘开始’);
throw new Error(“一个错误”);
} catch (err) {
// …
if(“can’t handle the error”) {
throw err;
}
} finally {
alert(‘清洗!’)
}
}
f(); // 清洗!
trying >>
这finally
是保证在这里进行清理。如果仅将代码放在的f()
末尾,则在这些情况下将无法运行该代码。