面试题答案
一键面试JavaScript事件循环机制对异步错误处理的影响
- 事件循环机制概述:JavaScript是单线程语言,事件循环机制负责协调执行任务。它有一个调用栈(call stack)用于执行同步任务,还有宏任务队列(macrotask queue)和微任务队列(microtask queue)。当调用栈为空时,事件循环会从宏任务队列中取出一个任务放入调用栈执行,执行完后检查微任务队列,将所有微任务依次放入调用栈执行,如此循环。
- 微任务队列中抛出错误:微任务通常由
Promise
的回调、MutationObserver
等产生。当微任务抛出错误时,如果没有被try - catch
块捕获,会向上冒泡到全局的unhandledrejection
事件处理程序。例如:
Promise.resolve()
.then(() => {
throw new Error('微任务中的错误');
})
.catch(err => {
console.log('捕获到微任务中的错误:', err.message);
});
window.addEventListener('unhandledrejection', event => {
console.log('全局捕获到未处理的微任务错误:', event.reason.message);
});
在上述代码中,如果.catch
块没有捕获到错误,unhandledrejection
事件会捕获到该错误。
3. 宏任务队列中抛出错误:宏任务包括setTimeout
、setInterval
、I/O
操作、UI渲染
等。当宏任务抛出错误时,如果没有在该宏任务内部的try - catch
块捕获,会向上冒泡到全局的uncaughtexception
事件处理程序(在Node.js环境下)或导致页面崩溃(在浏览器环境下)。例如:
setTimeout(() => {
throw new Error('宏任务中的错误');
}, 0);
process.on('uncaughtException', err => {
console.log('捕获到宏任务中的错误:', err.message);
});
在Node.js环境下,uncaughtException
事件可以捕获到宏任务中未处理的错误。
递归异步函数中错误处理
- 确保错误捕获:在递归异步函数中,为了确保错误能够被正确捕获,可以在每次递归调用时使用
try - catch
块。例如:
async function recursiveAsyncFunction(n) {
if (n <= 0) {
return;
}
try {
await new Promise((resolve) => setTimeout(resolve, 100));
if (Math.random() < 0.5) {
throw new Error('随机错误');
}
console.log('执行递归步骤', n);
await recursiveAsyncFunction(n - 1);
} catch (err) {
console.log('捕获到递归中的错误:', err.message);
}
}
recursiveAsyncFunction(5);
在上述代码中,try - catch
块可以捕获每次递归调用中可能抛出的错误。
2. 防止内存泄漏和程序崩溃:通过正确捕获错误并处理,避免错误向上冒泡未被处理导致程序崩溃。同时,在递归结束条件正确设置的情况下,不会导致无限递归进而引发内存泄漏。例如在上述代码中,if (n <= 0)
设置了递归结束条件,确保递归不会无限进行。