MST
星途 面试题库

面试题:Node.js微任务与宏任务中的错误处理策略

请详细阐述Node.js中微任务队列(如Promise的回调)和宏任务队列(如`setTimeout`、`setInterval`等)在异步编程中的执行顺序。当在微任务和宏任务中分别出现错误时,它们的错误传播和处理机制有何不同?如何确保在复杂的异步场景中,无论是微任务还是宏任务的错误都能得到妥善处理,且不会导致应用崩溃?
29.3万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

1. 执行顺序

  • 事件循环机制:Node.js 基于事件循环来处理异步操作。事件循环会不断检查调用栈是否为空,当调用栈为空时,会从任务队列中取出任务放入调用栈执行。
  • 宏任务队列:常见的宏任务包括 setTimeoutsetIntervalsetImmediateI/O 操作等。事件循环每次从宏任务队列中取出一个宏任务执行,执行完毕后,会检查微任务队列。
  • 微任务队列:常见的微任务有 Promise 的回调(.then.catch)、process.nextTick 等。微任务会在当前宏任务执行结束后,下一个宏任务开始之前执行。也就是说,事件循环在执行完一个宏任务后,会清空微任务队列中的所有微任务,然后再从宏任务队列中取下一个宏任务执行。

2. 错误传播和处理机制

  • 宏任务错误:宏任务中的错误通常不会直接影响其他宏任务或微任务。例如,setTimeout 回调中的错误不会导致后续的 setTimeout 回调或其他宏任务无法执行。如果宏任务中的错误没有被捕获,它会在该宏任务的作用域内抛出,可能会导致当前进程或线程出现问题(如 Node.js 进程崩溃),具体取决于运行环境。
  • 微任务错误:微任务中的错误会中断微任务队列的执行。如果一个 Promise 的 .then 回调中抛出错误,后续的 .then 回调将不会执行,而是直接进入 .catch 回调。如果没有 .catch 回调,错误会向上传播到全局的 unhandledRejection 事件(在 Node.js 中),可能导致应用出现未处理的拒绝情况。

3. 确保错误妥善处理,避免应用崩溃

  • 宏任务错误处理
    • 使用 try - catch:在宏任务回调内部使用 try - catch 块捕获错误,例如:
setTimeout(() => {
    try {
        // 可能出错的代码
        throw new Error('宏任务中的错误');
    } catch (error) {
        console.error('捕获宏任务中的错误:', error);
    }
}, 0);
  • 监听全局错误事件:在 Node.js 中,可以监听 uncaughtException 事件来捕获未处理的异常,避免进程崩溃:
process.on('uncaughtException', (error) => {
    console.error('捕获全局未处理的宏任务异常:', error);
});
  • 微任务错误处理
    • 使用 .catch 处理 Promise 错误:在每个 Promise 链中,确保有 .catch 回调来处理可能的错误:
Promise.resolve()
  .then(() => {
        throw new Error('微任务中的错误');
    })
  .catch((error) => {
        console.error('捕获微任务中的错误:', error);
    });
  • 监听 unhandledRejection 事件:在 Node.js 中,监听 unhandledRejection 事件来处理未处理的 Promise 拒绝:
process.on('unhandledRejection', (reason, promise) => {
    console.error('捕获未处理的微任务拒绝:', reason, promise);
});
  • 使用 async/await 结合 try - catch:在 async 函数中使用 try - catch 捕获错误,因为 await 会暂停函数执行,直到 Promise 被解决,所以可以很好地捕获错误:
async function asyncFunction() {
    try {
        await Promise.reject(new Error('微任务中的错误'));
    } catch (error) {
        console.error('捕获微任务中的错误:', error);
    }
}
asyncFunction();