参考链接
try catch不是万能的,不能捕获promise的错误。但可以promise接catch来捕获错误,如果有多层的promise,每层都要加catch。
代码示例
// 捕获失败
try {
new Promise((resolve,reject)=>{
throw Error(1)
})
} catch (e) {
console.error('catch error')
}
// 能捕获
try {
new Promise((resolve,reject)=>{
throw Error(1)
}).catch(e=>{
console.error('error catch!')
})
} catch (e) {
console.error('catch error', e)
}
// 多层 不能
try {
new Promise((resolve,reject)=>{
return new Promise(()=>{
throw new Error(1)
})
}).catch(e=>{
console.error('error catch!')
}
)
} catch (e) {
console.error('catch error', e)
}
// 每层都catch,然后reject外抛,能捕获
try {
new Promise((resolve,reject)=>{
return new Promise(()=>{
throw new Error(1)
}).catch(e=>{
return reject(e)
})
}).catch(e=>{
console.error('error catch!')
}
)
} catch (e) {
console.error('catch error', e)
}
这里的原理是啥?
参考这里,promise的executor里(就是这里)默认有个try catch,当有异常时就会执行reject并把异常作为参数。
我们知道try catch能捕获try代码块的异常,但如果异常在promise里抛出,那异常不是立即执行的,而是调用了reject,而reject是加到microtask里执行的,详细可以了解下javascript的event loop机制
比如如下代码
console.log(1)
new Promise((resolve) => {
console.log(2)
throw Error(4)
}).then((e) => {
console.log(e) })
console.log(3)
会输出1、2、3后,再抛出异常4。到异常4的时候,已经不在try catch的marcotask了,try catch里的部份已经执行完了,而是在microtask里处理这个异常,所以捕获不了
console.log(1)
new Promise((resolve) => {
console.log(2)
throw Error(4)
}).catch(e=>{
console.warn(e)})
console.log(3)
所以这样能捕获
这样也可以
new Promise(r=>{
try{
eee} catch(e){
console.warn(e)}
})
// ReferenceError: eee is not defined
但这样不行,同理setTimeout异步执行的,try里面的代码实际已经跑完了
try {
setTimeout(()=>{
eee})
}catch(e) {
console.warn(e)
}
还有一种方法也能捕获,加上await
async function getSomeValue() {
throw new Error('uh oh');
}
async function a() {
try {
const someValue = await getSomeValue();
} catch (error) {
console.warn(error);
}
}
await是等待promise resolve或reject后才继续执行之后的代码,那为啥在外面加try catch就能捕获到?是因为执行又回到macrotask了?