参考链接
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了?