MST

星途 面试题库

面试题:Node.js 中 Async Hooks 处理复杂异步场景错误

假设存在一个具有多层嵌套异步操作且包含多个异步循环的 Node.js 应用场景,如何使用 Async Hooks 准确地跟踪每个异步任务的错误,并将错误信息按照异步任务的执行顺序进行整理输出?请详细说明实现思路和关键代码片段。
41.6万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 引入async_hooks模块:该模块提供了跟踪异步资源生命周期的能力。
  2. 创建AsyncHook实例:利用async_hooks.createHook方法,在其回调函数中捕获异步任务的各种事件,如init(初始化)、destroy(销毁)等。
  3. 跟踪错误:在异步操作执行过程中,当捕获到错误时,将错误信息与对应的异步任务关联起来。
  4. 记录执行顺序:可以通过在init事件中为每个异步任务分配一个唯一标识符,并结合一个队列来记录异步任务的执行顺序。
  5. 整理输出:在所有异步任务完成后,按照记录的顺序输出错误信息。

关键代码片段

const asyncHooks = require('async_hooks');
const { performance } = require('perf_hooks');

// 用于存储异步任务及其错误信息
const asyncTasks = new Map();
// 用于记录异步任务执行顺序
const taskOrder = [];

const asyncHook = asyncHooks.createHook({
  init(asyncId, type, triggerAsyncId, resource) {
    // 为每个异步任务分配唯一标识符并记录到执行顺序队列
    taskOrder.push(asyncId);
    asyncTasks.set(asyncId, { type, error: null });
  },
  destroy(asyncId) {
    // 异步任务结束,这里可以做清理等操作
  },
  promiseRejectWithValue(asyncId, reason) {
    // 捕获Promise拒绝(错误)情况
    if (asyncTasks.has(asyncId)) {
      asyncTasks.get(asyncId).error = reason;
    }
  }
});
asyncHook.enable();

// 模拟多层嵌套异步操作和异步循环
async function nestedAsyncOperations() {
  try {
    await new Promise((resolve) => setTimeout(resolve, 100));
    for (let i = 0; i < 3; i++) {
      await new Promise((resolve, reject) => {
        setTimeout(() => {
          if (i === 1) {
            reject(new Error('模拟错误'));
          } else {
            resolve();
          }
        }, 100);
      });
    }
    await new Promise((resolve) => setTimeout(resolve, 100));
  } catch (error) {
    // 捕获外层错误
    const currentAsyncId = asyncHooks.executionAsyncId();
    if (asyncTasks.has(currentAsyncId)) {
      asyncTasks.get(currentAsyncId).error = error;
    }
  } finally {
    // 所有异步任务完成后整理输出错误信息
    const errorsInOrder = taskOrder.map(asyncId => asyncTasks.get(asyncId).error)
    .filter(error => error);
    console.log('按照执行顺序的错误信息:', errorsInOrder);
  }
}

nestedAsyncOperations();

在上述代码中:

  1. 首先引入了async_hooksperf_hooks模块。
  2. 创建了asyncHook实例并注册了initdestroypromiseRejectWithValue等回调函数。init用于初始化异步任务跟踪,destroy可用于清理,promiseRejectWithValue捕获Promise的拒绝错误。
  3. nestedAsyncOperations函数模拟了多层嵌套异步操作和异步循环。在循环中模拟了错误抛出。
  4. 最后在finally块中,按照记录的异步任务执行顺序整理并输出错误信息。