Spec-Zone.ru › Deno 2

async_hooks

Мы настоятельно не рекомендуем использовать API async_hooks. К большинству сценариев его использования можно применить другие API, в том числе:

  • AsyncLocalStorage отслеживает асинхронный контекст
  • process.getActiveResourcesInfo() отслеживает активные ресурсы

Модуль node:async_hooks предоставляет API для отслеживания асинхронных ресурсов. Его можно подключить с помощью:

import async_hooks from 'node:async_hooks';

Использование в Deno

import * as mod from "node:async_hooks";

класс AsyncLocalStorage

Использование в Deno

import { AsyncLocalStorage } from "node:async_hooks";

Этот класс создает хранилища, сохраняющие согласованность при выполнении асинхронных операций.

Хотя можно создать собственную реализацию на основе модуля node:async_hooks, предпочтительно использовать AsyncLocalStorage — это производительная реализация с безопасным управлением памятью, включающая существенные оптимизации, которые сложно реализовать самостоятельно.

В следующем примере AsyncLocalStorage используется для создания простого средства ведения журнала, которое присваивает идентификаторы входящим HTTP-запросам и добавляет их в сообщения, записываемые в журнал в рамках каждого запроса.

import http from 'node:http';
import { AsyncLocalStorage } from 'node:async_hooks';

const asyncLocalStorage = new AsyncLocalStorage();

function logWithId(msg) {
  const id = asyncLocalStorage.getStore();
  console.log(`${id !== undefined ? id : '-'}:`, msg);
}

let idSeq = 0;
http.createServer((req, res) => {
  asyncLocalStorage.run(idSeq++, () => {
    logWithId('start');
    // Imagine any chain of async operations here
    setImmediate(() => {
      logWithId('finish');
      res.end();
    });
  });
}).listen(8080);

http.get('http://localhost:8080');
http.get('http://localhost:8080');
// Prints:
//   0: start
//   1: start
//   0: finish
//   1: finish

Каждый экземпляр AsyncLocalStorage поддерживает независимый контекст хранилища. Одновременно могут безопасно существовать несколько экземпляров без риска взаимного влияния их данных.

Параметры типа

T

Методы

disable(): void

Отключает экземпляр AsyncLocalStorage. Все последующие вызовы asyncLocalStorage.getStore() будут возвращать undefined до тех пор, пока снова не будет вызван asyncLocalStorage.run() или asyncLocalStorage.enterWith().

При вызове asyncLocalStorage.disable() будут завершены все текущие контексты, связанные с экземпляром.

Перед сборкой мусора для asyncLocalStorage необходимо вызвать asyncLocalStorage.disable(). Это не относится к хранилищам, предоставляемым asyncLocalStorage, поскольку такие объекты собираются вместе с соответствующими асинхронными ресурсами.

Используйте этот метод, когда asyncLocalStorage больше не используется в текущем процессе.

enterWith(store: T): void

Переключается в контекст на оставшуюся часть текущего синхронного выполнения, а затем сохраняет хранилище при всех последующих асинхронных вызовах.

Пример:

const store = { id: 1 };
// Replaces previous store with the given store object
asyncLocalStorage.enterWith(store);
asyncLocalStorage.getStore(); // Returns the store object
someAsyncOperation(() => {
  asyncLocalStorage.getStore(); // Returns the same object
});

Этот переход будет действовать в течение всего синхронного выполнения. Это означает, что если, например, контекст был открыт в обработчике события, последующие обработчики событий также будут выполняться в этом контексте, если только они явно не привязаны к другому контексту с помощью AsyncResource. Поэтому следует предпочитать run() вместо enterWith(), если только нет веских причин использовать последний метод.

const store = { id: 1 };

emitter.on('my-event', () => {
  asyncLocalStorage.enterWith(store);
});
emitter.on('my-event', () => {
  asyncLocalStorage.getStore(); // Returns the same object
});

asyncLocalStorage.getStore(); // Returns undefined
emitter.emit('my-event');
asyncLocalStorage.getStore(); // Returns the same object
exit<
R,
TArgs extends any[],
>
(
callback: (...args: TArgs) => R,
...args: TArgs,
): R

Синхронно выполняет функцию вне контекста и возвращает ее результат. Хранилище недоступно внутри функции обратного вызова и асинхронных операций, созданных внутри нее. Любой вызов getStore() внутри функции обратного вызова всегда будет возвращать undefined.

Необязательные аргументы args передаются функции обратного вызова.

Если функция обратного вызова выбрасывает ошибку, exit() также выбрасывает эту ошибку. Этот вызов не влияет на трассировку стека, а контекст восстанавливается.

Пример:

// Within a call to run
try {
  asyncLocalStorage.getStore(); // Returns the store object or value
  asyncLocalStorage.exit(() => {
    asyncLocalStorage.getStore(); // Returns undefined
    throw new Error();
  });
} catch (e) {
  asyncLocalStorage.getStore(); // Returns the same object or value
  // The error will be caught here
}
getStore(): T | undefined

Возвращает текущее хранилище. Если вызван вне асинхронного контекста, инициализированного вызовом asyncLocalStorage.run() или asyncLocalStorage.enterWith(), возвращает undefined.

run<R>(
store: T,
callback: () => R,
): R

Синхронно выполняет функцию в контексте и возвращает ее результат. Хранилище недоступно вне функции обратного вызова. Оно доступно для любых асинхронных операций, созданных внутри функции обратного вызова.

Необязательные аргументы args передаются функции обратного вызова.

Если функция обратного вызова выбрасывает ошибку, run() также выбрасывает эту ошибку. Этот вызов не влияет на трассировку стека, а контекст закрывается.

Пример:

const store = { id: 2 };
try {
  asyncLocalStorage.run(store, () => {
    asyncLocalStorage.getStore(); // Returns the store object
    setTimeout(() => {
      asyncLocalStorage.getStore(); // Returns the store object
    }, 200);
    throw new Error();
  });
} catch (e) {
  asyncLocalStorage.getStore(); // Returns undefined
  // The error will be caught here
}
run<
R,
TArgs extends any[],
>
(
store: T,
callback: (...args: TArgs) => R,
...args: TArgs,
): R

Статические методы

bind<Func extends (...args: any[]) => any>(fn: Func): Func

Привязывает указанную функцию к текущему контексту выполнения.

snapshot(): <
R,
TArgs extends any[],
>
(
fn: (...args: TArgs) => R,
...args: TArgs,
) => R

Сохраняет текущий контекст выполнения и возвращает функцию, принимающую функцию в качестве аргумента. При каждом вызове возвращенная функция вызывает переданную ей функцию в сохраненном контексте.

const asyncLocalStorage = new AsyncLocalStorage();
const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
console.log(result);  // returns 123

AsyncLocalStorage.snapshot() может заменить AsyncResource для простого отслеживания асинхронного контекста, например:

class Foo {
  #runInAsyncScope = AsyncLocalStorage.snapshot();

  get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
}

const foo = asyncLocalStorage.run(123, () => new Foo());
console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123

класс AsyncResource

Использование в Deno

import { AsyncResource } from "node:async_hooks";
Совместимость с Deno

Реализация AsyncResource представляет собой неработающую заглушку.

Класс AsyncResource предназначен для расширения асинхронными ресурсами встраиваемой среды. Это позволяет пользователям легко инициировать события жизненного цикла собственных ресурсов.

Хук init срабатывает при создании экземпляра AsyncResource.

Ниже приводится обзор API AsyncResource.

import { AsyncResource, executionAsyncId } from 'node:async_hooks';

// AsyncResource() is meant to be extended. Instantiating a
// new AsyncResource() also triggers init. If triggerAsyncId is omitted then
// async_hook.executionAsyncId() is used.
const asyncResource = new AsyncResource(
  type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false },
);

// Run a function in the execution context of the resource. This will
// * establish the context of the resource
// * trigger the AsyncHooks before callbacks
// * call the provided function `fn` with the supplied arguments
// * trigger the AsyncHooks after callbacks
// * restore the original execution context
asyncResource.runInAsyncScope(fn, thisArg, ...args);

// Call AsyncHooks destroy callbacks.
asyncResource.emitDestroy();

// Return the unique ID assigned to the AsyncResource instance.
asyncResource.asyncId();

// Return the trigger ID for the AsyncResource instance.
asyncResource.triggerAsyncId();

Конструкторы

AsyncResource(
type: string,
triggerAsyncId?: number | AsyncResourceOptions,
)
новый

AsyncResource() предназначен для расширения. Создание экземпляра AsyncResource() также вызывает init. Если triggerAsyncId не указан, используется async_hook.executionAsyncId().

Методы

asyncId(): number
bind<Func extends (...args: any[]) => any>(fn: Func): Func

Привязывает указанную функцию к области действия этого AsyncResource.

emitDestroy(): this

Вызывает все хуки destroy. Этот метод следует вызывать только один раз. При повторном вызове будет выброшена ошибка. Его необходимо вызвать вручную. Если сборщик мусора удалит ресурс, хуки destroy вызваны не будут.

runInAsyncScope<
This,
Result,
>
(
fn: (
this: This,
...args: any[],
) => Result
,
thisArg?: This,
...args: any[],
): Result

Вызывает переданную функцию с указанными аргументами в контексте выполнения асинхронного ресурса. Метод устанавливает контекст, запускает обратные вызовы AsyncHooks before, вызывает функцию, запускает обратные вызовы AsyncHooks after, а затем восстанавливает исходный контекст выполнения.

triggerAsyncId(): number

Статические методы

bind<
Func extends (
this: ThisArg,
...args: any[],
) => any
,
ThisArg,
>
(
fn: Func,
type?: string,
thisArg?: ThisArg,
): Func

Привязывает указанную функцию к текущему контексту выполнения.


функция createHook

Использование в Deno

import { createHook } from "node:async_hooks";
createHook(callbacks: HookCallbacks): AsyncHook
Совместимость с Deno

Реализация createHook представляет собой неработающую заглушку.

Регистрирует функции, вызываемые при различных событиях жизненного цикла каждой асинхронной операции.

Обратные вызовы init()/before()/after()/destroy() вызываются при соответствующих асинхронных событиях в течение жизненного цикла ресурса.

Все обратные вызовы необязательны. Например, если нужно отслеживать только очистку ресурсов, достаточно передать обратный вызов destroy. Подробная информация обо всех функциях, которые можно передать в callbacks, приведена в разделе Hook Callbacks.

import { createHook } from 'node:async_hooks';

const asyncHook = createHook({
  init(asyncId, type, triggerAsyncId, resource) { },
  destroy(asyncId) { },
});

Обратные вызовы наследуются по цепочке прототипов:

class MyAsyncCallbacks {
  init(asyncId, type, triggerAsyncId, resource) { }
  destroy(asyncId) {}
}

class MyAddedCallbacks extends MyAsyncCallbacks {
  before(asyncId) { }
  after(asyncId) { }
}

const asyncHook = async_hooks.createHook(new MyAddedCallbacks());

Поскольку промисы являются асинхронными ресурсами, жизненный цикл которых отслеживается механизмом async hooks, обратные вызовы init(), before(), after() и destroy() не должны быть асинхронными функциями, возвращающими промисы.

Параметры

callbacks: HookCallbacks

Hook Callbacks для регистрации

Возвращаемый тип

AsyncHook

Экземпляр, используемый для отключения и включения хуков


функция executionAsyncId

Использование в Deno

import { executionAsyncId } from "node:async_hooks";
executionAsyncId(): number
Совместимость с Deno

Реализация executionAsyncId представляет собой неработающую заглушку.

import { executionAsyncId } from 'node:async_hooks';
import fs from 'node:fs';

console.log(executionAsyncId());  // 1 - bootstrap
const path = '.';
fs.open(path, 'r', (err, fd) => {
  console.log(executionAsyncId());  // 6 - open()
});

Идентификатор, возвращаемый executionAsyncId(), связан со временем выполнения, а не с причинно-следственными связями (которые описывает triggerAsyncId()):

const server = net.createServer((conn) => {
  // Returns the ID of the server, not of the new connection, because the
  // callback runs in the execution scope of the server's MakeCallback().
  async_hooks.executionAsyncId();

}).listen(port, () => {
  // Returns the ID of a TickObject (process.nextTick()) because all
  // callbacks passed to .listen() are wrapped in a nextTick().
  async_hooks.executionAsyncId();
});

По умолчанию контексты промисов могут не получать точные executionAsyncIds. См. раздел об отслеживании выполнения промисов.

Возвращаемый тип

number

asyncId текущего контекста выполнения. Полезен для отслеживания момента вызова.


функция executionAsyncResource

Использование в Deno

import { executionAsyncResource } from "node:async_hooks";
executionAsyncResource(): object

Объекты ресурсов, возвращаемые executionAsyncResource(), чаще всего являются внутренними объектами дескрипторов Node.js с недокументированными API. Использование любых функций или свойств таких объектов может привести к сбою приложения, поэтому этого следует избегать.

При вызове executionAsyncResource() в контексте выполнения верхнего уровня возвращается пустой объект, поскольку нет доступного объекта дескриптора или запроса. Однако объект, представляющий верхний уровень, может быть полезен.

import { open } from 'node:fs';
import { executionAsyncId, executionAsyncResource } from 'node:async_hooks';

console.log(executionAsyncId(), executionAsyncResource());  // 1 {}
open(new URL(import.meta.url), 'r', (err, fd) => {
  console.log(executionAsyncId(), executionAsyncResource());  // 7 FSReqWrap
});

Это можно использовать для реализации локального хранилища продолжения без отслеживающего Map для хранения метаданных:

import { createServer } from 'node:http';
import {
  executionAsyncId,
  executionAsyncResource,
  createHook,
} from 'node:async_hooks';
const sym = Symbol('state'); // Private symbol to avoid pollution

createHook({
  init(asyncId, type, triggerAsyncId, resource) {
    const cr = executionAsyncResource();
    if (cr) {
      resource[sym] = cr[sym];
    }
  },
}).enable();

const server = createServer((req, res) => {
  executionAsyncResource()[sym] = { state: req.url };
  setTimeout(function() {
    res.end(JSON.stringify(executionAsyncResource()[sym]));
  }, 100);
}).listen(3000);

Возвращаемый тип

object

Ресурс, представляющий текущее выполнение. Полезен для хранения данных в ресурсе.


функция triggerAsyncId

Использование в Deno

import { triggerAsyncId } from "node:async_hooks";
triggerAsyncId(): number
const server = net.createServer((conn) => {
  // The resource that caused (or triggered) this callback to be called
  // was that of the new connection. Thus the return value of triggerAsyncId()
  // is the asyncId of "conn".
  async_hooks.triggerAsyncId();

}).listen(port, () => {
  // Even though all callbacks passed to .listen() are wrapped in a nextTick()
  // the callback itself exists because the call to the server's .listen()
  // was made. So the return value would be the ID of the server.
  async_hooks.triggerAsyncId();
});

По умолчанию контексты промисов могут не получать допустимые triggerAsyncId. См. раздел об отслеживании выполнения промисов.

Возвращаемый тип

number

Идентификатор ресурса, ответственного за вызов выполняемого в данный момент обратного вызова.


интерфейс AsyncHook

Использование в Deno

import { type AsyncHook } from "node:async_hooks";

Методы

enable(): this

Включает обратные вызовы указанного экземпляра AsyncHook. Если обратные вызовы не заданы, включение ничего не делает.

disable(): this

Отключает обратные вызовы указанного экземпляра AsyncHook в общем пуле обратных вызовов AsyncHook, предназначенных для выполнения. После отключения хук не будет вызываться, пока его снова не включат.


интерфейс AsyncResourceOptions

Использование в Deno

import { type AsyncResourceOptions } from "node:async_hooks";

Свойства

triggerAsyncId: number | undefined
необязательное

Идентификатор контекста выполнения, создавшего это асинхронное событие.

requireManualDestroy: boolean | undefined
необязательное

Отключает автоматический вызов emitDestroy при сборке мусора для объекта. Обычно этот параметр не требуется задавать (даже если emitDestroy вызывается вручную), кроме случаев, когда извлекается asyncId ресурса и вместе с ним вызывается emitDestroy чувствительного API.


интерфейс HookCallbacks

Использование в Deno

import { type HookCallbacks } from "node:async_hooks";

Методы

init(
asyncId: number,
type: string,
triggerAsyncId: number,
resource: object,
): void
необязательное

Вызывается при создании экземпляра класса, который может инициировать асинхронное событие.

before(asyncId: number): void
необязательное

При запуске асинхронной операции или ее завершении вызывается обратный вызов, уведомляющий пользователя. Обратный вызов before вызывается непосредственно перед указанным обратным вызовом.

after(asyncId: number): void
необязательное

Вызывается сразу после завершения обратного вызова, указанного в before.

Если во время выполнения обратного вызова возникает необработанное исключение, after запускается после отправки события 'uncaughtException' или выполнения обработчика domain.

promiseResolve(asyncId: number): void
необязательное

Вызывается при вызове resolve() для промиса. Это может происходить не в том же идентификаторе выполнения, что и сам промис.

destroy(asyncId: number): void
необязательное

Вызывается после уничтожения ресурса, соответствующего asyncId


© 2018–2025 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/api/node/async_hooks

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API