← Назад к вопросам

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

2.8 Senior🔥 101 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Связь между node:async_hooks и AsyncLocalStorage

AsyncLocalStorage и модуль async_hooks — это две стороны одной медали в Node.js для управления асинхронным контекстом. Понимание их взаимосвязи критически важно для правильной работы с контекстной информацией в распределённых системах.

Что такое async_hooks?

async_hooks — это низкоуровневый API Node.js, который позволяет отслеживать жизненный цикл асинхронных ресурсов (таймеры, промисы, сокеты и т.д.). Он предоставляет хуки для перехвата:

  • init — создание асинхронного ресурса
  • before — начало выполнения колбэка ресурса
  • after — завершение выполнения колбэка
  • destroy — уничтожение ресурса
const async_hooks = require("async_hooks");

const hook = async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    console.log(`Ресурс ${type} создан с ID ${asyncId}`);
  },
  before(asyncId) {
    console.log(`Выполнение ресурса ${asyncId}`);
  },
  after(asyncId) {
    console.log(`Завершение ресурса ${asyncId}`);
  },
});

hook.enable();

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

AsyncLocalStorage построен на основе async_hooks и предоставляет простой интерфейс для хранения данных, изолированных в пределах одной цепочки выполнения:

const { AsyncLocalStorage } = require("async_hooks");

const userStorage = new AsyncLocalStorage();

// Установить значение для текущей цепочки
userStorage.run({ userId: 123 }, () => {
  console.log(userStorage.getStore()); // { userId: 123 }
  
  // Значение доступно даже в асинхронных операциях
  setTimeout(() => {
    console.log(userStorage.getStore()); // { userId: 123 }
  }, 100);
});

console.log(userStorage.getStore()); // undefined — контекст потерян

Как они взаимосвязаны?

  1. AsyncLocalStorage использует async_hooks внутри — когда вы вызываете .run(), AsyncLocalStorage регистрирует хуки для отслеживания асинхронных ресурсов

  2. Автоматическое распространение контекста — благодаря async_hooks, данные, установленные в .run(), автоматически доступны во всех асинхронных операциях внутри этой цепочки

  3. Изоляция контекста — каждая цепочка имеет свой контекст, что крайне важно для многопользовательского сервера

Практический пример: логирование с контекстом

const { AsyncLocalStorage } = require("async_hooks");
const express = require("express");

const requestContext = new AsyncLocalStorage();

const app = express();

app.use((req, res, next) => {
  requestContext.run({ requestId: req.id, userId: req.user?.id }, () => {
    next();
  });
});

function log(message) {
  const context = requestContext.getStore();
  console.log(`[${context?.requestId}] ${message}`);
}

app.get("/api/users/:id", async (req, res) => {
  log("Начало обработки запроса");
  
  // Данные контекста сохраняются во всех асинхронных операциях
  const user = await db.findUser(req.params.id);
  log("Пользователь найден");
  
  res.json(user);
});

Когда использовать async_hooks напрямую?

Напрямую async_hooks нужен для:

  • Отладки и профилирования асинхронного кода
  • Отслеживания утечек ресурсов
  • Детального анализа performance

Для обычной работы с контекстом всегда используй AsyncLocalStorage — это безопаснее и проще.