(*) Stability: 1 - Experimental
Czym jest async_hooks?
Jest mechanizmem pozwalającym na śledzenie "życia" zasobów asynchronicznych.
Zasoby asynchroniczne reprezentują obiekty z powiązanym wywołaniem.
Krótka historia
- Pierwsza implementacja nosiła nazwę
AsyncListeneri została zaimplementowana w wersjiNodejs0.11, ale została usunięta w wersji 0.12 - Kolejna implementacja pojawiła się pod nazwą
AsyncWrap(async_wrap) i została dodana doNodejsw wersji 0.12.
async_wrapbył nieoficjalnym i niedokumentowanym dodatkiem wNodejsw wersjach < 8. async_hooksjest najnowszą i oficjalną paczką pozwalającą na podpięcie hook'ów do asynchronicznych wywołań. Implementacja pojawiła się wNodejs w wersji8.
Api
import async_hooks from 'node:async_hooks';
// Return the ID of the current execution context.
async_hooks.executionAsyncId();
// Return the ID of the handle responsible for triggering the callback
async_hooks.triggerAsyncId();
// Create a new AsyncHook instance. All of these callbacks are optional.
const asyncHook = async_hooks.createHook({
init,
before,
after,
destroy,
promiseResolve
});
// Allow callbacks of this AsyncHook instance to call.
asyncHook.enable();
// Disable listening for new asynchronous events.
asyncHook.disable();createHook
import async_hooks from 'node:async_hooks';
async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) {
// called when an async resource is initialized.
},
before(asyncId) {
// before() is called just before the resource's callback is called.
},
after(asyncId) {
// after() is called just after the resource's callback has finished.
},
destroy(asyncId) {
// destroy() is called when the resource is destroyed.
},
promiseResolve(asyncId) {
// called when the resolve function of the Promise constructor is invoked
}
}).enable();Obsługiwane typy w async_hooks
FSEVENTWRAP, FSREQCALLBACK, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPINCOMINGMESSAGE, HTTPCLIENTREQUEST, JSSTREAM, PIPECONNECTWRAP, PIPEWRAP, PROCESSWRAP, QUERYWRAP, SHUTDOWNWRAP, SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVERWRAP, TCPWRAP, TTYWRAP, UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST, RANDOMBYTESREQUEST, TLSWRAP, Microtask, Timeout, Immediate, TickObject, Promise
Uwaga!
Ponieważ logowanie do konsoli jest operacją asynchroniczną, console.log() spowoduje wywołanie callback'ów AsyncHook. Używanie console.log() lub podobnych operacji asynchronicznych wewnątrz funkcji AsyncHook spowoduje nieskończoną rekurencję.
// Przykład ominięcia petli i wyświetlenia logu w konsoli
import { writeFileSync } from 'node:fs';
import { format } from 'node:util';
writeFileSync(1, `${format(...args)}\n`);
// lub
process._rawDebug('some log');init
Promise.resolve()
.then(🎈() => {
return void 0;
});before
Promise.resolve()
.then(() => 🎈{
return void 0;
});after
Promise.resolve()
.then(() => {
return void 0;
}🎈);destroy
Promise.resolve()
.then(() => {
return void 0;
});
// ...
🎈promiseResolve
Promise.resolve()
.then(() => {
return void 0;🎈
});Demo
Wbudowana klasa modułu async_hooks pozwalająca w optymalny sposób korzystać z wyizolowanego stanu.
AsyncLocalStorage
Api
import { AsyncLocalStorage } from 'node:async_hooks';
const store = {};
// Creates a new instance of AsyncLocalStorage.
const asyncLocalStorage = new AsyncLocalStorage();
/// Runs a function synchronously within
// a context and returns its return value.
asyncLocalStorage.run(store, () => {});
// Returns the current store
asyncLocalStorage.getStore();
// // Replaces previous store with the given store object
asyncLocalStorage.enterWith(store);
// Disables the instance of AsyncLocalStorage
asyncLocalStorage.disable();
// Runs a function synchronously outside of a context and returns its return value.
asyncLocalStorage.exit(() => {
asyncLocalStorage.getStore(); // Returns undefined
throw new Error();
});Demo
Przykazanie XI
"Coś za coś"

A co na to przeglądarka?
Przypadki użycia
- Pomiary wydajności (profiling)
- Oddzielny globalny kontekst dla każdego nowego zapytania (execution context)(uproszczone zbieranie logów, wspólny kontekst użytkownika, itp.)
- Zaawansowane śledzenie przepływu
Dziękuję za uwagę!
- https://nodejs.org/api/async_hooks.html
- https://medium.com/nmc-techblog/the-power-of-async-hooks-in-node-js-8a2a84238acb
- https://itnext.io/a-pragmatic-overview-of-async-hooks-api-in-node-js-e514b31460e9
- https://blog.scottlogic.com/2019/03/04/lambda-global-state.html
async_hooks
By Piotr Tarasiuk
async_hooks
- 109