try-catch 为什么无法捕获异步错误?如何正确捕获?
请说明 try-catch 无法捕获 setTimeout/Promise/reject 等异步错误的原因,以及正确的错误捕获方式。
回答
我是大山
原因:try-catch 只能捕获同一执行栈中同步抛出的错误。异步回调在后续事件循环中执行时,try-catch 所在的上下文已出栈。
无法捕获的例子:
try {
setTimeout(() => {
throw new Error('异步错误'); // 不会被外层的 try-catch 捕获
}, 100);
} catch (e) {
console.log('不会执行');
}
正确捕获方式:
1. setTimeout/setInterval 回调内部捕获:
setTimeout(() => {
try {
// 可能出错的代码
} catch (e) {
console.error(e);
}
}, 100);
2. Promise 错误:
doAsync().catch(err => console.error(err));
// 或 async/await
async function run() {
try {
await doAsync();
} catch (err) {
console.error(err);
}
}
3. 事件回调错误:
button.addEventListener('click', async () => {
try {
await fetchData();
} catch (err) {
console.error(err);
}
});
4. 全局兜底:
window.onerror/window.addEventListener('error')— 捕获同步 + 资源错误window.addEventListener('unhandledrejection')— 捕获未处理的 Promise reject
原则:每个异步操作的错误必须在同一异步上下文中捕获,或通过全局错误监听器兜底。