Как связаны node:async_hooks и AsyncLocalStorage?nodejs-4

Эти два API представляют разные уровни абстракции для работы с асинхронным контекстом в Node.js. Давайте разберем их взаимосвязь.

1. Базовые концепции

async_hooks — низкоуровневый API

Предоставляет механизм отслеживания асинхронных операций:

  • Создание/уничтожение асинхронных ресурсов
  • Вызовы колбэков
  • Переходы между контекстами

Пример:

const async_hooks = require('node:async_hooks');
const hook = async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    console.log(`Init: ${type} (${asyncId})`);
  }
});
hook.enable();

AsyncLocalStorage — высокоуровневая абстракция

Предоставляет удобный API для хранения данных в асинхронном контексте:

const { AsyncLocalStorage } = require('node:async_context');
const als = new AsyncLocalStorage();
als.run({ key: 'value' }, () => {
  console.log(als.getStore()); // { key: 'value' }
});

2. Архитектурная связь

AsyncLocalStorage построен поверх async_hooks и использует его для:

  1. Отслеживания контекстов:

    • При вызове als.run() создается новый асинхронный контекст
    • async_hooks отслеживает переходы между контекстами
  2. Хранения данных:

    • Внутри используется async_hooks.executionAsyncId()
    • Данные привязываются к текущему asyncId
  3. Очистки ресурсов:

    • Использует async_hooks для детектирования завершения асинхронных операций

3. Практическая взаимозависимость

Как AsyncLocalStorage использует async_hooks:

// Упрощенная реализация ALS
class SimpleALS {
  constructor() {
    this.storage = new Map();
    this.hook = async_hooks.createHook({
      init: (asyncId, type, triggerAsyncId) => {
        if (this.storage.has(triggerAsyncId)) {
          this.storage.set(asyncId, this.storage.get(triggerAsyncId));
        }
      },
      destroy: (asyncId) => {
        this.storage.delete(asyncId);
      }
    });
    this.hook.enable();
  }
}

Критические отличия:

  1. Производительность: AsyncLocalStorage оптимизирован и быстрее чистого async_hooks
  2. Безопасность: ALS защищает от утечек памяти
  3. Удобство: Предоставляет простой API вместо ручного управления контекстами

4. Совместное использование

Пример интеграции:

const als = new AsyncLocalStorage();
const hook = async_hooks.createHook({
  before(asyncId) {
    const store = als.getStore();
    if (store) {
      console.log(`Context before ${asyncId}:`, store);
    }
  }
});

als.run({ requestId: 42 }, () => {
  hook.enable();
  setTimeout(() => {
    // Сохраняет контекст благодаря ALS и async_hooks
    console.log(als.getStore()); // { requestId: 42 }
  }, 100);
});

Резюмируем

  1. Иерархия: AsyncLocalStorage — высокоуровневая надстройка над async_hooks
  2. Зависимость: ALS реализован через механизмы async_hooks
  3. Оптимизация: ALS решает проблемы производительности чистого async_hooks
  4. Сценарии:
    • async_hooks для глубокого контроля и мониторинга
    • AsyncLocalStorage для повседневной работы с контекстом

Используйте ALS для большинства задач, а async_hooks — когда нужен максимальный контроль над асинхронными операциями.