1、語法
try語句包含了由一個或者多個語句組成的try塊,和至少一個catch塊或者一個finally塊的其中一個,或者兩個兼有,下面是三種形式的try聲明:
try...catch
try...finally
try...catch...finally
try {
// 需要被執行的語句
} catch (err) {
// 如果在try塊里有異常被拋出時執行的語句
} finally {
// 在try語句塊之后執行的語句塊。無論是否有異常拋出或捕獲這些語句都將執行。
}
上述代碼中,try塊中的語句首先被執行。如果運行中發生了錯誤,控制就會轉移到位于catch塊中語句,其中括號中的err參數被作為例外變量傳遞。否則,catch塊的語句被跳過不執行。無論是發生錯誤還是catch塊中的語句執行完畢,或者沒有發生任何錯誤try塊中的語句執行完畢,最后將執行finally塊中的語句。
2、舉例
1、無錯誤情況
try {
alert('開始執行 try1'); // (1)
alert('開始執行 try2'); // (2)
} catch (err) {
alert('catch 被忽略,因為沒有 error,不會被執行'); // (3)
}
上面代碼會彈出‘開始執行 try1’和開始執行 try2,但是不會彈出‘catch 被忽略,因為沒有 error’
2、有錯誤情況
try {
alert('開始執行 try1'); // (1)
throw "此處拋出錯誤"; //try塊里到此結束,不會在執行下邊的try2
alert('try2,不會被執行'); // (2)
} catch (err) {
alert('出現了 error,此句被執行'); // (3)
}
上面代碼會彈出‘開始執行 try1’和‘出現了 error,此句被執行’
3、try...catch 僅對可以運行的代碼 error 有效。
要使得 try...catch 能工作,代碼必須是可執行的。換句話說,它必須是有效的 JavaScript 代碼。
如果代碼包含語法錯誤,那么 try..catch 將無法正常工作,例如下邊代碼出現了一行逗號:
try {
,,,,,,//js引擎無法理解這段代碼,它是無效的
throw "此處不會拋出錯誤"; //不會執行
alert('try2,此句不會被執行'); // (2)
} catch (err) {
alert('此句不會被執行'); // (3)
}
4、try catch 嵌套
try {
try {
throw new Error("try1");
}
finally {
console.log("finally");
}
}
catch (err) {
console.error("outer", err.message);
}
會輸出
// finally
// outer try1
try {
try {
throw new Error("try1");
}
catch (err) {
console.error("inner", err.message);
}
finally {
console.log("finally");
}
}
catch (err) {
console.error("outer", err.message);
}
會輸出
// inner try1
// finally
try {
try {
throw new Error("try1");
}
catch (err) {
console.error("inner", err.message);
// return 如果我在此處寫個return會是什么結果? (下邊的報錯信息肯定不會拋出了,當然return必須是在函數里)
throw new Error("try2"); //試想一下,如何把此句代碼放在下邊的finally里會怎么輸出?(結果一樣)
}
finally {
console.log("finally");
}
}
catch (err) {
console.error("outer", err.message);
}
會輸出
// inner try1
// finally
// outer try2
try {
try {
throw new Error("try1");
}
catch (err) {
console.error("inner", err.message);
throw new Error("try2");
}
finally {
console.log("finally");
return //終止了錯誤的拋出
}
}
catch (err) {
console.error("outer", err.message); //不會被執行
}
會輸出
// inner try1
// finally
5、try...catch 異步任務
try...catch 不會捕獲到異步錯誤:
try {
setTimeout(()=>{
throw new Error('錯誤信息')
}, 1000);
} catch (err) {
alert( "alert不會執行" );
}
因為 try...catch 包裹了計劃要執行的函數,該函數有延遲,這時js引擎已經離開了 try...catch 結構,也就是上下文環境已經改變,所以無法捕獲異步任務里的錯誤。為了捕獲到計劃的函數中的異常,那么 try...catch 必須在這個函數內,如下
setTimeout(() => {
try {
throw new Error("錯誤信息");
} catch (err) {
alert("alert會執行");
}
}, 1000);
6、try...catch promise對象的異常捕獲
try...catch 也不會捕獲微任務,如下代碼是捕獲不到錯誤的。
function test(){
Promise.resolve('1').then(()=>{
throw new Error('錯誤信息')
})
}
try {
test()
} catch (err) {
alert("不工作");
}
try {
Promise.reject('錯誤信息');
} catch(e) {
console.log(e.message);
}
//這2段代碼try,catch都不會捕獲到錯誤信息,因為 promise 內部的錯誤不會冒泡出來,而是被 promise 吃掉了,只有通過 promise.catch 才可以捕獲。
那我們順帶看下promise.catch
Promise.reject('錯誤信息').then(v=>{
return '1'
}).catch(v=>{
console.log(v) // 錯誤信息
})
Promise.resolve('1').then(v=>{
throw '錯誤信息'
}).catch(v=>{
console.log(v) // 錯誤信息
})
你會發現promise.reject的錯誤和promise.resolve里throw的錯誤都被promise.catch方法捕獲。
7、try...catch async/await 的異常捕獲
// 例子1
async function test() {
throw new Error('錯誤信息');
return 0;
}
test().then().catch(e => console.log(e.message)); // 錯誤信息(可以捕獲到錯誤信息)
// 例子2
function promiseFn(){
return new Promise((resolve, reject) => {
throw new Error("錯誤信息");
});
}
async function test() {
try {
const res = await promiseFn();
} catch (e) {
console.log(e.message);//錯誤信息(可以捕獲到錯誤信息)
}
}
test();
// 例子3
function promiseFn(){
new Promise((resolve, reject) => {
throw new Error("錯誤信息");
});
}
async function test() {
try {
const res = await promiseFn();
} catch (e) {
console.log(e.message);//不會執行 (捕獲不到錯誤信息)
}
}
test();
// 例子3和例子2的區別在于promiseFn函數里沒有了return了
// 例子4
function promiseFn(){
return Promise.reject('錯誤信息')
}
async function test() {
try {
const res = await promiseFn();
} catch (e) {
console.log(e);//錯誤信息(可以捕獲到錯誤信息)
}
}
test();
8、全局監聽拋出的錯誤
以上所有異常,僅通過 try catch、then 捕獲同步、異步錯誤。這些是局部錯誤捕獲手段,當我們無法保證所有代碼都處理了異常時,可以進行全局異常監控,一般有兩種方法:
window.addEventListener('error')
window.addEventListener('unhandledrejection')
error 可以監聽所有同步、異步的運行時錯誤,但無法監聽語法、接口、資源加載錯誤。而 unhandledrejection 可以監聽到 Promise 中拋出的,未被 .catch 捕獲的錯誤。
window.addEventListener('error', function (e) {
var error = e.error;
console.log(error);//錯誤信息
})
document.querySelector('button').addEventListener('click', () => {
throw new Error('錯誤信息')
})