错误处理,“try…catch”
try {
// 执行此处代码
} catch(err) {
// 如果发生错误,跳转至此处
// err 是一个 error 对象
} finally {
// 无论怎样都会在 try/catch 之后执行
}
try…catch 仅对运行时的 error有效
- 要使得
try..catch
能工作,代码必须是可执行的。如果代码包含语法错误,那么try..catch
将无法正常工作。
try…catch 同步工作
- 如果在"计划的"代码中发生异常,则不会捕获到
//try..catch 包裹了稍后要执行的函数,这时引擎已经离开了try..catch结构
try {
setTimeout(function() {
noSuchVariable; // 脚本将在这里停止运行
}, 1000);
} catch (e) {
alert( "won't work" );
}
- 想要捕获到计划的函数中的异常,那么
try..catch
必须在这个函数内
setTimeout(function() {
try {
noSuchVariable; // try..catch 处理 error 了!
} catch {
alert( "error is caught here!" );
}
}, 1000);
Error 对象
属性:
- name:Error名称(对于一个未定义的变量,名称是 “ReferenceError”。)
- message:关于 error 的详细文字描述。
- stack:当前的调用栈:用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。
try {
lalala; // error, variable is not defined!
} catch(err) {
alert(err.name); // ReferenceError
alert(err.message); // lalala is not defined
alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)
// 也可以将一个 error 作为整体显示出来as a whole
// Error 信息被转换为像 "name: message" 这样的字符串
alert(err); // ReferenceError: lalala is not defined
}
可选的"catch"绑定
- 如果我们不需要 error 的详细信息,catch 也可以忽略它:
try {
// ...
} catch { // <-- 没有 (err)
// ...
}
使用"try…catch"
- 如果 json 格式错误,JSON.parse 就会生成一个 error
- 所以要捕获到这个异常,输出错误信息
let json = "{ bad json }";
try {
let user = JSON.parse(json); // <-- 当出现一个 error 时...
alert( user.name ); // 不工作
} catch (e) {
// ...执行会跳转到这里并继续执行
alert( "Our apologies, the data has errors, we'll try to request it one more time." );
alert( e.name );
alert( e.message );
}
自定义异常
"Throw"操作符
- throw 操作符会生成一个error对象
语法:throw <error object>
内建的标准error的构造器
- Error、SyntaxError、ReferenceError、TypeError等。
语法:
let error = new Error(message);
// 或
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...
- 对于内建的error;name属性是构造器的名字;message来自参数。
let error = new Error("Things happen o_O");
alert(error.name); // Error
alert(error.message); // Things happen o_O
代码
- 如果解析字符串产生的user对象缺少name属性,抛出异常
let json = '{ "age": 30 }'; // 不完整的数据
try {
let user = JSON.parse(json); // <-- 没有 error
if (!user.name) {
throw new SyntaxError("Incomplete data: no name"); // (*)
}
alert( user.name );
} catch(e) {
alert( "JSON Error: " + e.message ); // JSON Error: Incomplete data: no name
}
再次抛出(rethrowing)
在上面的例子中,我们使用 try..catch
来处理不正确的数据。但是在 try {...}
块中是否可能发生 另一个预料之外的 error
?例如编程错误(未定义变量)或其他错误,而不仅仅是这种“不正确的数据”。
let json = '{ "age": 30 }'; // 不完整的数据
try {
user = JSON.parse(json); // <-- 忘记在 user 前放置 "let"
// ...
} catch(err) {
alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined
// (实际上并没有 JSON Error)
}
catch 应该只处理它知道的 error,并“抛出”所有其他 error。
“再次抛出(rethrowing)”技术可以被更详细地解释为:
- Catch 捕获所有 error。
- 在 catch(err) {…} 块中,我们对 error 对象 err 进行分析。
- 如果我们不知道如何处理它,那我们就 throw err。
通常,我们可以使用 instance 操作符判断错误类型
let json = '{ "age": 30 }'; // 不完整的数据
try {
let user = JSON.parse(json);
if (!user.name) {
throw new SyntaxError("Incomplete data: no name");
}
blabla(); // 预料之外的 error
alert( user.name );
} catch(e) {
if (e instanceof SyntaxError) {
alert( "JSON Error: " + e.message );
} else {
throw e; // 再次抛出 (*)
}
}
- 如果不知到如何处理这个异常,可以再次抛出,被外部的try…catch结构捕获
function readData() {
let json = '{ "age": 30 }';
try {
blabla(); // error!
} catch (e) {
if (!(e instanceof SyntaxError)) {
throw e; // 再次抛出(不知道如何处理它)
}
}
}
try {
readData();
} catch (e) {
alert( "External catch got: " + e ); // 捕获了它!
}
try…catch…finally
- finally如果存在,它在所有情况下都会被执行(无论函数以return还是throw完成都无关紧要)
try {
... 尝试执行的代码 ...
} catch(e) {
... 处理 error ...
} finally {
... 总是会执行的代码 ...
}
- 如果我们使用 let 在 try 块中声明变量,那么该变量将只在 try 块中可见。
try…finally
- 当我们不想在这儿处理 error(让它们 fall through),但是需要确保我们启动的处理需要被完成。
function func() {
// 开始执行需要被完成的操作(比如测量)
try {
// ...
} finally {
// 完成前面我们需要完成的那件事儿,即使 try 中的执行失败了
}
}
使用finally的优势
比较下面两个代码片段:
try {
work work
} catch (e) {
handle errors
} finally {
cleanup the working space
}
try {
work work
} catch (e) {
handle errors
}
cleanup the working space
- 当try…catch中有return(或throw)时,finally中的代码肯定会执行,第二种中后面的语句肯定不会执行
全局catch
- 在 try…catch 结构外有一个致命的 error,然后脚本死亡了。这个 error 就像编程错误或其他可怕的事儿那样。
- message:Error信息
- url:发生error的脚本的URL
- line、col:发生error处的代码的行号和列号
- error:Error对象
window.onerror = function(message, url, line, col, error) {
// ...
};
例:
<script>
window.onerror = function(message, url, line, col, error) {
alert(`${message}\n At ${line}:${col} of ${url}`);
};
function readData() {
badFunc(); // 啊,出问题了!
}
readData();
</script>