關於JS的異常捕獲,主要分爲兩種,一種爲同步情況下的異常捕獲,一種爲一步執行下的異常捕獲;異常捕獲的【坑】主要集中在異步場景。
同步
在同步場景下,簡單粗暴,直接使用try/catch解決問題。
(function() {
try {
// catch: ReferenceError: obj is not defined
console.log(obj.error)
} catch (e) {
console.log('catch:', e)
}
})();
catch: ReferenceError: obj is not defined
at <anonymous>:4:17
at <anonymous>:8:3
異步
setTimeout異常
在異步場景下,按照上面的異常捕獲方式是無法捕獲到異常的,如下
// 無法捕獲到異常
(function() {
try {
setTimeout(function() {
console.log(obj.error)
}, 500)
} catch (e) {
console.log('catch:', e)
}
})()
Uncaught ReferenceError: obj is not defined
at <anonymous>:4:19
at i (init.js:1)
之所以無法捕獲到異常,原因在於異步方法執行時,主流程已執行完畢,try/catch已經退出函數調用棧;正確的異常捕獲如下:
(function() {
try {
setTimeout(function() {
try {
console.log(obj.error)
} catch (e) {
// 此處捕獲到異常
console.log('catch1:', e)
}
}, 500)
} catch (e) {
// 此處無法捕獲到異常
console.log('catch2:', e)
}
})()
catch1: ReferenceError: obj is not defined
at <anonymous>:5:21
at i (init.js:1)
從這裏可以看出,最外層的try/catch是不生效的,可以去掉。
promise異常
首先通過兩端代碼來看promise的異常捕獲情況
代碼一:
(function() {
try {
const promise = new Promise((resolve, reject) => {
setTimeout(function() {
// 此處的異常無法被捕獲
console.log('1', obj.error)
resolve(100)
})
})
promise.then(result => {
console.log('result:', result)
}).catch(error => {
// 此處無法捕獲到異常
console.log('catch1:', error)
})
} catch (e) {
// 此處無法捕獲到異常
console.log('catch2:', e)
}
})();
Uncaught ReferenceError: obj is not defined
at <anonymous>:6:26
at i (init.js:1)
代碼二:
(function() {
try {
const promise = new Promise((resolve, reject) => {
console.log(obj.error)
setTimeout(function() {
resolve(100)
})
})
promise.then(result => {
console.log('result:', result)
}).catch(error => {
// 此處捕獲到異常
console.log('catch1:', error)
})
} catch (e) {
// 此處無法捕獲到異常
console.log('catch2:', e)
}
})()
catch1: ReferenceError: obj is not defined
at <anonymous>:4:19
at new Promise (<anonymous>)
at <anonymous>:3:21
at <anonymous>:19:3
總結:
- 最外層的try/catch對於promise中的異常捕獲完全無效
- new Promise()中的異步異常(setTimeout)只能在內部捕獲
- new Promise()中的同步異常只能通過catch捕獲
核心:熟悉EventLoop就知道,每個任務使用獨立的函數調用棧;所以,每一個task都需要單獨捕獲異常;使用promise.catch能夠捕獲到promise任務的異常。
async/await異常
追尋talk is cheap,show me the code
的原則,這裏直接上驗證代碼,讓實際結果來說明一切。
function f() {
return new Promise((resolve, reject) => {
console.log(obj.error)
setTimeout(function() {
// 1.這裏的異常只能在setTimeout內部使用try/catch捕獲
// console.log(obj.error)
resolve(100)
})
})
}
async function main() {
try {
const result = await f().catch(e => {
// 2.優先捕獲到異常
console.log('catch1:', e)
})
console.log(result)
} catch (e) {
// 3.如果沒有catch1,這裏也能捕獲到異常
console.log('catch2:', e)
}
}
main()
總結:
- new Promise()中的異步異常(setTimeout)只能在內部捕獲
- 可以使用
.catch
也可使用try/catch
來捕獲異常,其中.catch
優先級較高
作者公衆號: