Error handling, "try..catch"
程式執行會發生很多錯誤,原因千奇百怪,錯誤會讓程式停止執行,我們可以用 try..catch 讓程式除了停止執行外,可以對錯誤進行處理。
The “try…catch” syntax
// syntax
try {
// code...
} catch (err) {
// error handling
}
// 沒有錯誤發生
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");
// 錯誤發生
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 occurred!`); // (3) <--
}
alert("...Then the execution continues");
// try..catch 能夠運作的前提是程式碼是有效的程式碼,因為引擎讀不懂程式碼,所以不會執行 try..catch
try {
{{{{{{{{{{{{
} catch(e) {
alert("The engine can't understand this code, it's invalid");
}
// 如果有非同步的程式碼,因為已經執行完 try..catch,所以對非同步的 setTimeout 裡的程式碼
// 不會捕捉錯誤
try {
setTimeout(function() {
noSuchVariable; // script will die here
}, 1000);
} catch (e) {
alert( "won't work" );
}
// 要捕捉 setTimeout 裡程式碼的錯誤,要在裡面加上 try..catch
setTimeout(function() {
try {
noSuchVariable; // try..catch handles the error!
} catch {
alert( "error is caught here!" );
}
}, 1000);
Error object
// 捕捉到的錯誤,會返回作為 catch 的參數
try {
// ...
} catch(err) { // <-- the "error object", could use another word instead of err
// ...
}
// 錯誤物件包含 name message 2 個屬性,還有很多非標準的屬性,最多被廣泛運用的是 stack
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 ...
// Can also show an error as a whole
// The error is converted to string as "name: message"
alert(err); // ReferenceError: lalala is not defined
}
Optional “catch” binding
// 最近新增的如果不需要錯誤訊息,catch 可以忽略它
try {
// ...
} catch {
// error object omitted
}
Using “try…catch”
// 實際使用 try..catch 情形
let json = '{"name":"John", "age": 30}'; // data from the server
let user = JSON.parse(json); // convert the text representation to JS object
// now user is an object with properties from the string
alert( user.name ); // John
alert( user.age ); // 30let json = "{ bad json }";
// 用 try..catch 處理錯誤,我們只印出錯誤訊息,但可以做其他處理,
// 发送一个新的网络请求,给用户提供另外的选择,把异常信息发送给记录日志的工具
try {
let user = JSON.parse(json); // <-- 当这里抛出异常...
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 );
}
Throwing our own errors
// 程式碼運行正常,但沒有我們要的 name 屬性。
let json = '{ "age": 30 }'; // incomplete data
try {
let user = JSON.parse(json); // <-- no errors
alert( user.name ); // no name!
} catch (e) {
alert( "doesn't execute" );
}
// 可以用 throw 自定義錯誤
throw <error object>
// syntax,有內建的錯誤建構函式 Error、 SyntaxError、ReferenceError、TypeError 等等
let error = new Error(message);
// or
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...
// example,name 屬性是建構函式的名稱,message 屬性來自丟入的參數
let error = new Error("Things happen o_O");
alert(error.name); // Error
alert(error.message); // Things happen o_O
try {
JSON.parse("{ bad json o_O }");
} catch(e) {
alert(e.name); // SyntaxError
alert(e.message); // Unexpected token o in JSON at position 0
}
// 實際使用
let json = '{ "age": 30 }'; // incomplete data
try {
let user = JSON.parse(json); // <-- no errors
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 發生預料之外的異常,這裡拋出 JSON Error 的錯誤是不對的錯誤訊息
let json = '{ "age": 30 }'; // incomplete data
try {
user = JSON.parse(json); // <-- forgot to put "let" before user
// ...
} catch(err) {
alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined
// (no JSON Error actually)
}
// 我們可以通過其他方式知道正確的錯誤訊息
try {
user = { /*...*/ };
} catch(e) {
alert(e.name); // "ReferenceError" for accessing an undefined variable
}
// catch 捕捉已知的錯誤,拋出其他未知的錯誤
// rethrowing 的規則,捕捉所有錯誤,catch(err) {...} 處理已知錯誤,未知錯誤 throw err
let json = '{ "age": 30 }'; // 不完整的数据
try {
let user = JSON.parse(json);
if (!user.name) {
throw new SyntaxError("Incomplete data: no name");
}
blabla(); // 预料之外的异常
alert( user.name );
} catch(e) {
if (e.name == "SyntaxError") {
alert( "JSON Error: " + e.message );
} else {
throw e; // rethrow (*)
}
}
// 未知的錯誤會被外層 try..catch 處理
function readData() {
let json = '{ "age": 30 }';
try {
// ...
blabla(); // 异常!
} catch (e) {
// ...
if (e.name != 'SyntaxError') {
throw e; // 重新抛出(不知道如何处理它)
}
}
}
try {
readData();
} catch (e) {
alert( "External catch got: " + e ); // 捕获到!
}
try…catch…finally
// syntax,不果有沒有錯誤發生 finally 都會執行
try {
... try to execute the code ...
} catch(e) {
... handle errors ...
} finally {
... execute always ...
}
// If you answer “Yes”, then try -> catch -> finally.
// If you say “No”, then try -> finally.
try {
alert( 'try' );
if (confirm('Make an error?')) BAD_CODE();
} catch (e) {
alert( 'catch' );
} finally {
alert( 'finally' );
}
// 不論有沒有結果都會印出計算時間
let num = +prompt("Enter a positive integer number?", 35)
let diff, result;
function fib(n) {
if (n < 0 || Math.trunc(n) != n) {
throw new Error("Must not be negative, and also an integer.");
}
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
}
let start = Date.now();
try {
result = fib(num);
} catch (e) {
result = 0;
} finally {
diff = Date.now() - start;
}
alert(result || "error occured");
alert( `execution took ${diff}ms` );
// try..catch 結束執行包含 return,finally 會先被執行,才會執行外部程式碼。
function func() {
try {
return 1;
} catch (e) {
/* ... */
} finally {
alert( 'finally' );
}
}
alert( func() ); // first works alert from finally, and then this one
// 如果暫時不想處理錯誤,用 try..finally 確保程式執行完畢
function func() {
// 开始做需要被完成的操作(比如测量)
try {
// ...
} finally {
// 完成前面要做的事情,即使 try 里面执行失败
}
}
Global catch
// try..catch 之外的程式碼,出現了嚴重錯誤,在瀏覽器環境可以使用 window.onerror 處理
window.onerror = function(message, url, line, col, error) {
// ...
};
// example,不是去處理所有錯誤,而是提供開發者錯誤訊息
<script>
window.onerror = function(message, url, line, col, error) {
alert(`${message}\n At ${line}:${col} of ${url}`);
};
function readData() {
badFunc(); // 哦,出问题了!
}
readData();
</script>
Last updated