「这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战」
不管你多么精通编程,有时我们的脚本总还是会出现错误。可能是因为编写出错,或是与预期不同的用户输入,或是错误的服务端响应以及其他数千种原因。
通常,如果发生错误,脚本就会“死亡”(立即停止),如果你不希望脚本直接停止,那么你可以使用 try..catch
,来进行错误的“捕获(catch)”。
try..catch语法
try..catch
结构由两部分组成:try
和 catch
:
try {
// 代码...
} catch (err) {
// 错误捕获
}
💡 执行步骤:
- 先执行
try {...}
中的代码 - 没有错误,忽略
catch(err)
:执行到try
的末尾并跳过catch
继续执行。 - 出现错误,执行停止
try
,控制流转向catch(err)
的开头。变量err
(我们可以使用任何名称)将包含一个 error 对象,该对象包含了所发生事件的详细信息。
所以try {…}
块内的错误不会让脚本停止,并且你还可以在 catch
中处理这个错误。
try..catch失效的情况
代码本身就不可执行
try..catch
只对有效的 JavaScript 代码有用,什么意思呢?
🎨 如下示例:
- 如果是变量未定义的错误,可以被捕获到;
- 但是如果是像这种多写了一个【花括号】的语法错误,并不能正常运行。
非同步工作
如果在“计划的(scheduled)”代码中发生异常,例如在 setTimeout
中,则 try..catch
不会捕获到异常:
🎨 示例:
可以看到以下示例运行结果中,未定义的变量错误没有被捕获到,而是直接报错了。这是因为try..catch
包裹了计划要执行的函数,该函数本身要稍后才执行,这时引擎已经离开了 try..catch
结构。
💡 改进
如果你想捕获到计划的(scheduled)函数中的异常,那么 try..catch
必须在这个函数内
catch里的Error对象
发生错误时,JavaScript 生成一个包含有关其详细信息的对象。然后将该对象作为参数传递给 catch
catch里的error 对象具有两个主要属性:
name
Error 名称。例如,对于一个未定义的变量,名称是"ReferenceError"
。message
关于 error 的详细文字描述。
还有其他非标准的属性在大多数环境中可用。其中被最广泛使用和支持的是:
stack
当前的调用栈:用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。
throw语句
throw
语句用来抛出一个用户自定义的异常。当前函数的执行将被停止(throw
之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个catch
块。如果调用者函数中没有catch
块,程序将会终止。
🎨 示例:
从技术上说,你可以将任何东西用作 error 对象。
throw "Error2"; // 抛出了一个值为字符串的异常
throw 42; // 抛出了一个值为整数42的异常
throw true; // 抛出了一个值为true的异常
但最好使用对象,最好使用具有 name
和 message
属性的对象(某种程度上保持与内建 error 的兼容性)。
try...catch...finally
try..catch
结构可能还有一个代码子句(clause):finally
。
try {
... 尝试执行的代码 ...
} catch(e) {
... 处理 error ...
} finally {
... 总是会执行的代码 ...
}
finally
子句(clause)通常用在:当我们开始做某事的时候,希望无论出现什么情况都要完成完成某个任务。
try..finally
try..finally
结构也是可以正常执行的,当不想在这儿处理 error,但是需要确保启动的处理被完成时可以使用这个结构。
function func() {
// 开始执行需要被完成的操作(比如测量)
try {
// ...
} finally {
// 完成前面我们需要完成的那件事儿,即使 try 中的执行失败了
}
}
这段代码由于没有 catch
,所以 try
中的 error 总是会使代码执行跳转至函数 func()
外。但是,在跳出之前需要执行 finally
中的代码。
参考资料:
🎨【点赞】【关注】不迷路,更多前端干货等你解锁
往期推荐