js错误处理机制

2020 / 02 / 07

window.onerror和window.onunhandledrejection

window.onerror可以捕捉到同一个域下的js脚本的宏任务的错误,而promise抛出的错误不会被捕捉到,比如下边的demo,timer error和async error都可以捕捉到,但是promise的捕捉不到。

window.addEventListener('error', (error) => {
console.log('window listener get error: ', error)
})

Promise.resolve()
.then(() => {
throw 'lalal error' // 不能被捕捉到
})

setTimeout(() => {
throw 'timer error' // 可以被捕捉到
}, 1000)

throw 'async error' // 可以被捕捉到

对此浏览器还提供了一个事件,叫做unhandlerehection,就是未处理的promise错误。

window.addEventListener('unhandledrejection', (error) => {
console.log('window promise error listener get error: ', error)
})

关于这点可以理解为凡是阻塞宏任务运行的错误都会被window捕捉到。window是宏任务运行的根容器,如果一个错误逃过了层层捕捉,但最后是不能逃过全局的错误处理事件的,但是promise作为微任务被另外一个部门接管了,所以window就不会去干涉了。

try catch和promise.prototype.catch

try catch同样无法捕捉异步的错误,包括微任务和宏任务中的异步错误。假如过一个错误被try catch捕捉了,并且处理了,那么他是不会触发window.onerror事件的。也就是说try catch是专注在当前这个宏任务的,管不到下一个宏任务中,更管不到微任务里去。

try {
Promise.reject('error 1') // 捕捉不到
} catch(err) {
console.log(err)
}

try {
setTimeout(() => {
throw 'error 2' // 捕捉不到
}, 500)
} catch(err) {
console.log(err)
}

而async await中的异步promise错误可以被try catch捕捉到。如果需要捕捉宏任务的异步错误的话,把宏任务的异步的写法改成promise就也能被捕捉到了。

const foo = async () => {
try {
await Promise.reject('error 1') // 可以捕捉到
} catch (err) {
console.log(err)
}

try {
await new Promise((resolve, reject) => {
setTimeout(() => {
reject('error 2') // 可以被捕捉到
}, 1000)
})
} catch (err) {
console.log(err)
}

setTimeout(() => {
throw 'error 3' // 不能被捕捉到
}, 1000)
}

foo()

promise的原型方法catch可以捕捉promise中发生的任何reject错误(promise中同步的throw 也会被当作reject错误,但异步中的throw不会被reject)。

之所以try catch可以捕捉到await中的错误,是因为async本身就是个语法糖,这点可以理解为在async函数中,对try catch方法做了特定的处理,会对异步中的promise的回调函数每一层都包裹一个try catch。

写评论
全部评论