11cb0ef41Sopenharmony_ci# Async hooks
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci<!--introduced_in=v8.1.0-->
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci> Stability: 1 - Experimental. Please migrate away from this API, if you can.
61cb0ef41Sopenharmony_ci> We do not recommend using the [`createHook`][], [`AsyncHook`][], and
71cb0ef41Sopenharmony_ci> [`executionAsyncResource`][] APIs as they have usability issues, safety risks,
81cb0ef41Sopenharmony_ci> and performance implications. Async context tracking use cases are better
91cb0ef41Sopenharmony_ci> served by the stable [`AsyncLocalStorage`][] API. If you have a use case for
101cb0ef41Sopenharmony_ci> `createHook`, `AsyncHook`, or `executionAsyncResource` beyond the context
111cb0ef41Sopenharmony_ci> tracking need solved by [`AsyncLocalStorage`][] or diagnostics data currently
121cb0ef41Sopenharmony_ci> provided by [Diagnostics Channel][], please open an issue at
131cb0ef41Sopenharmony_ci> <https://github.com/nodejs/node/issues> describing your use case so we can
141cb0ef41Sopenharmony_ci> create a more purpose-focused API.
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci<!-- source_link=lib/async_hooks.js -->
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciWe strongly discourage the use of the `async_hooks` API.
191cb0ef41Sopenharmony_ciOther APIs that can cover most of its use cases include:
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci* [`AsyncLocalStorage`][] tracks async context
221cb0ef41Sopenharmony_ci* [`process.getActiveResourcesInfo()`][] tracks active resources
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciThe `node:async_hooks` module provides an API to track asynchronous resources.
251cb0ef41Sopenharmony_ciIt can be accessed using:
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci```mjs
281cb0ef41Sopenharmony_ciimport async_hooks from 'node:async_hooks';
291cb0ef41Sopenharmony_ci```
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci```cjs
321cb0ef41Sopenharmony_ciconst async_hooks = require('node:async_hooks');
331cb0ef41Sopenharmony_ci```
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci## Terminology
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciAn asynchronous resource represents an object with an associated callback.
381cb0ef41Sopenharmony_ciThis callback may be called multiple times, such as the `'connection'`
391cb0ef41Sopenharmony_cievent in `net.createServer()`, or just a single time like in `fs.open()`.
401cb0ef41Sopenharmony_ciA resource can also be closed before the callback is called. `AsyncHook` does
411cb0ef41Sopenharmony_cinot explicitly distinguish between these different cases but will represent them
421cb0ef41Sopenharmony_cias the abstract concept that is a resource.
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ciIf [`Worker`][]s are used, each thread has an independent `async_hooks`
451cb0ef41Sopenharmony_ciinterface, and each thread will use a new set of async IDs.
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci## Overview
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ciFollowing is a simple overview of the public API.
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci```mjs
521cb0ef41Sopenharmony_ciimport async_hooks from 'node:async_hooks';
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci// Return the ID of the current execution context.
551cb0ef41Sopenharmony_ciconst eid = async_hooks.executionAsyncId();
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci// Return the ID of the handle responsible for triggering the callback of the
581cb0ef41Sopenharmony_ci// current execution scope to call.
591cb0ef41Sopenharmony_ciconst tid = async_hooks.triggerAsyncId();
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci// Create a new AsyncHook instance. All of these callbacks are optional.
621cb0ef41Sopenharmony_ciconst asyncHook =
631cb0ef41Sopenharmony_ci    async_hooks.createHook({ init, before, after, destroy, promiseResolve });
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci// Allow callbacks of this AsyncHook instance to call. This is not an implicit
661cb0ef41Sopenharmony_ci// action after running the constructor, and must be explicitly run to begin
671cb0ef41Sopenharmony_ci// executing callbacks.
681cb0ef41Sopenharmony_ciasyncHook.enable();
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci// Disable listening for new asynchronous events.
711cb0ef41Sopenharmony_ciasyncHook.disable();
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci//
741cb0ef41Sopenharmony_ci// The following are the callbacks that can be passed to createHook().
751cb0ef41Sopenharmony_ci//
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci// init() is called during object construction. The resource may not have
781cb0ef41Sopenharmony_ci// completed construction when this callback runs. Therefore, all fields of the
791cb0ef41Sopenharmony_ci// resource referenced by "asyncId" may not have been populated.
801cb0ef41Sopenharmony_cifunction init(asyncId, type, triggerAsyncId, resource) { }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci// before() is called just before the resource's callback is called. It can be
831cb0ef41Sopenharmony_ci// called 0-N times for handles (such as TCPWrap), and will be called exactly 1
841cb0ef41Sopenharmony_ci// time for requests (such as FSReqCallback).
851cb0ef41Sopenharmony_cifunction before(asyncId) { }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci// after() is called just after the resource's callback has finished.
881cb0ef41Sopenharmony_cifunction after(asyncId) { }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci// destroy() is called when the resource is destroyed.
911cb0ef41Sopenharmony_cifunction destroy(asyncId) { }
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci// promiseResolve() is called only for promise resources, when the
941cb0ef41Sopenharmony_ci// resolve() function passed to the Promise constructor is invoked
951cb0ef41Sopenharmony_ci// (either directly or through other means of resolving a promise).
961cb0ef41Sopenharmony_cifunction promiseResolve(asyncId) { }
971cb0ef41Sopenharmony_ci```
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci```cjs
1001cb0ef41Sopenharmony_ciconst async_hooks = require('node:async_hooks');
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci// Return the ID of the current execution context.
1031cb0ef41Sopenharmony_ciconst eid = async_hooks.executionAsyncId();
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci// Return the ID of the handle responsible for triggering the callback of the
1061cb0ef41Sopenharmony_ci// current execution scope to call.
1071cb0ef41Sopenharmony_ciconst tid = async_hooks.triggerAsyncId();
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci// Create a new AsyncHook instance. All of these callbacks are optional.
1101cb0ef41Sopenharmony_ciconst asyncHook =
1111cb0ef41Sopenharmony_ci    async_hooks.createHook({ init, before, after, destroy, promiseResolve });
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci// Allow callbacks of this AsyncHook instance to call. This is not an implicit
1141cb0ef41Sopenharmony_ci// action after running the constructor, and must be explicitly run to begin
1151cb0ef41Sopenharmony_ci// executing callbacks.
1161cb0ef41Sopenharmony_ciasyncHook.enable();
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci// Disable listening for new asynchronous events.
1191cb0ef41Sopenharmony_ciasyncHook.disable();
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci//
1221cb0ef41Sopenharmony_ci// The following are the callbacks that can be passed to createHook().
1231cb0ef41Sopenharmony_ci//
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci// init() is called during object construction. The resource may not have
1261cb0ef41Sopenharmony_ci// completed construction when this callback runs. Therefore, all fields of the
1271cb0ef41Sopenharmony_ci// resource referenced by "asyncId" may not have been populated.
1281cb0ef41Sopenharmony_cifunction init(asyncId, type, triggerAsyncId, resource) { }
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci// before() is called just before the resource's callback is called. It can be
1311cb0ef41Sopenharmony_ci// called 0-N times for handles (such as TCPWrap), and will be called exactly 1
1321cb0ef41Sopenharmony_ci// time for requests (such as FSReqCallback).
1331cb0ef41Sopenharmony_cifunction before(asyncId) { }
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci// after() is called just after the resource's callback has finished.
1361cb0ef41Sopenharmony_cifunction after(asyncId) { }
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci// destroy() is called when the resource is destroyed.
1391cb0ef41Sopenharmony_cifunction destroy(asyncId) { }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci// promiseResolve() is called only for promise resources, when the
1421cb0ef41Sopenharmony_ci// resolve() function passed to the Promise constructor is invoked
1431cb0ef41Sopenharmony_ci// (either directly or through other means of resolving a promise).
1441cb0ef41Sopenharmony_cifunction promiseResolve(asyncId) { }
1451cb0ef41Sopenharmony_ci```
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci## `async_hooks.createHook(callbacks)`
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci<!-- YAML
1501cb0ef41Sopenharmony_ciadded: v8.1.0
1511cb0ef41Sopenharmony_ci-->
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci* `callbacks` {Object} The [Hook Callbacks][] to register
1541cb0ef41Sopenharmony_ci  * `init` {Function} The [`init` callback][].
1551cb0ef41Sopenharmony_ci  * `before` {Function} The [`before` callback][].
1561cb0ef41Sopenharmony_ci  * `after` {Function} The [`after` callback][].
1571cb0ef41Sopenharmony_ci  * `destroy` {Function} The [`destroy` callback][].
1581cb0ef41Sopenharmony_ci  * `promiseResolve` {Function} The [`promiseResolve` callback][].
1591cb0ef41Sopenharmony_ci* Returns: {AsyncHook} Instance used for disabling and enabling hooks
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ciRegisters functions to be called for different lifetime events of each async
1621cb0ef41Sopenharmony_cioperation.
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ciThe callbacks `init()`/`before()`/`after()`/`destroy()` are called for the
1651cb0ef41Sopenharmony_cirespective asynchronous event during a resource's lifetime.
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ciAll callbacks are optional. For example, if only resource cleanup needs to
1681cb0ef41Sopenharmony_cibe tracked, then only the `destroy` callback needs to be passed. The
1691cb0ef41Sopenharmony_cispecifics of all functions that can be passed to `callbacks` is in the
1701cb0ef41Sopenharmony_ci[Hook Callbacks][] section.
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci```mjs
1731cb0ef41Sopenharmony_ciimport { createHook } from 'node:async_hooks';
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ciconst asyncHook = createHook({
1761cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId, resource) { },
1771cb0ef41Sopenharmony_ci  destroy(asyncId) { },
1781cb0ef41Sopenharmony_ci});
1791cb0ef41Sopenharmony_ci```
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci```cjs
1821cb0ef41Sopenharmony_ciconst async_hooks = require('node:async_hooks');
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ciconst asyncHook = async_hooks.createHook({
1851cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId, resource) { },
1861cb0ef41Sopenharmony_ci  destroy(asyncId) { },
1871cb0ef41Sopenharmony_ci});
1881cb0ef41Sopenharmony_ci```
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ciThe callbacks will be inherited via the prototype chain:
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ci```js
1931cb0ef41Sopenharmony_ciclass MyAsyncCallbacks {
1941cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId, resource) { }
1951cb0ef41Sopenharmony_ci  destroy(asyncId) {}
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ciclass MyAddedCallbacks extends MyAsyncCallbacks {
1991cb0ef41Sopenharmony_ci  before(asyncId) { }
2001cb0ef41Sopenharmony_ci  after(asyncId) { }
2011cb0ef41Sopenharmony_ci}
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ciconst asyncHook = async_hooks.createHook(new MyAddedCallbacks());
2041cb0ef41Sopenharmony_ci```
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ciBecause promises are asynchronous resources whose lifecycle is tracked
2071cb0ef41Sopenharmony_civia the async hooks mechanism, the `init()`, `before()`, `after()`, and
2081cb0ef41Sopenharmony_ci`destroy()` callbacks _must not_ be async functions that return promises.
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci### Error handling
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ciIf any `AsyncHook` callbacks throw, the application will print the stack trace
2131cb0ef41Sopenharmony_ciand exit. The exit path does follow that of an uncaught exception, but
2141cb0ef41Sopenharmony_ciall `'uncaughtException'` listeners are removed, thus forcing the process to
2151cb0ef41Sopenharmony_ciexit. The `'exit'` callbacks will still be called unless the application is run
2161cb0ef41Sopenharmony_ciwith `--abort-on-uncaught-exception`, in which case a stack trace will be
2171cb0ef41Sopenharmony_ciprinted and the application exits, leaving a core file.
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ciThe reason for this error handling behavior is that these callbacks are running
2201cb0ef41Sopenharmony_ciat potentially volatile points in an object's lifetime, for example during
2211cb0ef41Sopenharmony_ciclass construction and destruction. Because of this, it is deemed necessary to
2221cb0ef41Sopenharmony_cibring down the process quickly in order to prevent an unintentional abort in the
2231cb0ef41Sopenharmony_cifuture. This is subject to change in the future if a comprehensive analysis is
2241cb0ef41Sopenharmony_ciperformed to ensure an exception can follow the normal control flow without
2251cb0ef41Sopenharmony_ciunintentional side effects.
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci### Printing in `AsyncHook` callbacks
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ciBecause printing to the console is an asynchronous operation, `console.log()`
2301cb0ef41Sopenharmony_ciwill cause `AsyncHook` callbacks to be called. Using `console.log()` or
2311cb0ef41Sopenharmony_cisimilar asynchronous operations inside an `AsyncHook` callback function will
2321cb0ef41Sopenharmony_cicause an infinite recursion. An easy solution to this when debugging is to use a
2331cb0ef41Sopenharmony_cisynchronous logging operation such as `fs.writeFileSync(file, msg, flag)`.
2341cb0ef41Sopenharmony_ciThis will print to the file and will not invoke `AsyncHook` recursively because
2351cb0ef41Sopenharmony_ciit is synchronous.
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci```mjs
2381cb0ef41Sopenharmony_ciimport { writeFileSync } from 'node:fs';
2391cb0ef41Sopenharmony_ciimport { format } from 'node:util';
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_cifunction debug(...args) {
2421cb0ef41Sopenharmony_ci  // Use a function like this one when debugging inside an AsyncHook callback
2431cb0ef41Sopenharmony_ci  writeFileSync('log.out', `${format(...args)}\n`, { flag: 'a' });
2441cb0ef41Sopenharmony_ci}
2451cb0ef41Sopenharmony_ci```
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci```cjs
2481cb0ef41Sopenharmony_ciconst fs = require('node:fs');
2491cb0ef41Sopenharmony_ciconst util = require('node:util');
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_cifunction debug(...args) {
2521cb0ef41Sopenharmony_ci  // Use a function like this one when debugging inside an AsyncHook callback
2531cb0ef41Sopenharmony_ci  fs.writeFileSync('log.out', `${util.format(...args)}\n`, { flag: 'a' });
2541cb0ef41Sopenharmony_ci}
2551cb0ef41Sopenharmony_ci```
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ciIf an asynchronous operation is needed for logging, it is possible to keep
2581cb0ef41Sopenharmony_citrack of what caused the asynchronous operation using the information
2591cb0ef41Sopenharmony_ciprovided by `AsyncHook` itself. The logging should then be skipped when
2601cb0ef41Sopenharmony_ciit was the logging itself that caused the `AsyncHook` callback to be called. By
2611cb0ef41Sopenharmony_cidoing this, the otherwise infinite recursion is broken.
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci## Class: `AsyncHook`
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ciThe class `AsyncHook` exposes an interface for tracking lifetime events
2661cb0ef41Sopenharmony_ciof asynchronous operations.
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci### `asyncHook.enable()`
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci* Returns: {AsyncHook} A reference to `asyncHook`.
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ciEnable the callbacks for a given `AsyncHook` instance. If no callbacks are
2731cb0ef41Sopenharmony_ciprovided, enabling is a no-op.
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ciThe `AsyncHook` instance is disabled by default. If the `AsyncHook` instance
2761cb0ef41Sopenharmony_cishould be enabled immediately after creation, the following pattern can be used.
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci```mjs
2791cb0ef41Sopenharmony_ciimport { createHook } from 'node:async_hooks';
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ciconst hook = createHook(callbacks).enable();
2821cb0ef41Sopenharmony_ci```
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci```cjs
2851cb0ef41Sopenharmony_ciconst async_hooks = require('node:async_hooks');
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ciconst hook = async_hooks.createHook(callbacks).enable();
2881cb0ef41Sopenharmony_ci```
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci### `asyncHook.disable()`
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci* Returns: {AsyncHook} A reference to `asyncHook`.
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ciDisable the callbacks for a given `AsyncHook` instance from the global pool of
2951cb0ef41Sopenharmony_ci`AsyncHook` callbacks to be executed. Once a hook has been disabled it will not
2961cb0ef41Sopenharmony_cibe called again until enabled.
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ciFor API consistency `disable()` also returns the `AsyncHook` instance.
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci### Hook callbacks
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ciKey events in the lifetime of asynchronous events have been categorized into
3031cb0ef41Sopenharmony_cifour areas: instantiation, before/after the callback is called, and when the
3041cb0ef41Sopenharmony_ciinstance is destroyed.
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci#### `init(asyncId, type, triggerAsyncId, resource)`
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci* `asyncId` {number} A unique ID for the async resource.
3091cb0ef41Sopenharmony_ci* `type` {string} The type of the async resource.
3101cb0ef41Sopenharmony_ci* `triggerAsyncId` {number} The unique ID of the async resource in whose
3111cb0ef41Sopenharmony_ci  execution context this async resource was created.
3121cb0ef41Sopenharmony_ci* `resource` {Object} Reference to the resource representing the async
3131cb0ef41Sopenharmony_ci  operation, needs to be released during _destroy_.
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ciCalled when a class is constructed that has the _possibility_ to emit an
3161cb0ef41Sopenharmony_ciasynchronous event. This _does not_ mean the instance must call
3171cb0ef41Sopenharmony_ci`before`/`after` before `destroy` is called, only that the possibility
3181cb0ef41Sopenharmony_ciexists.
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ciThis behavior can be observed by doing something like opening a resource then
3211cb0ef41Sopenharmony_ciclosing it before the resource can be used. The following snippet demonstrates
3221cb0ef41Sopenharmony_cithis.
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci```mjs
3251cb0ef41Sopenharmony_ciimport { createServer } from 'node:net';
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_cicreateServer().listen(function() { this.close(); });
3281cb0ef41Sopenharmony_ci// OR
3291cb0ef41Sopenharmony_ciclearTimeout(setTimeout(() => {}, 10));
3301cb0ef41Sopenharmony_ci```
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci```cjs
3331cb0ef41Sopenharmony_cirequire('node:net').createServer().listen(function() { this.close(); });
3341cb0ef41Sopenharmony_ci// OR
3351cb0ef41Sopenharmony_ciclearTimeout(setTimeout(() => {}, 10));
3361cb0ef41Sopenharmony_ci```
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ciEvery new resource is assigned an ID that is unique within the scope of the
3391cb0ef41Sopenharmony_cicurrent Node.js instance.
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci##### `type`
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ciThe `type` is a string identifying the type of resource that caused
3441cb0ef41Sopenharmony_ci`init` to be called. Generally, it will correspond to the name of the
3451cb0ef41Sopenharmony_ciresource's constructor.
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ciThe `type` of resources created by Node.js itself can change in any Node.js
3481cb0ef41Sopenharmony_cirelease. Valid values include `TLSWRAP`,
3491cb0ef41Sopenharmony_ci`TCPWRAP`, `TCPSERVERWRAP`, `GETADDRINFOREQWRAP`, `FSREQCALLBACK`,
3501cb0ef41Sopenharmony_ci`Microtask`, and `Timeout`. Inspect the source code of the Node.js version used
3511cb0ef41Sopenharmony_cito get the full list.
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ciFurthermore users of [`AsyncResource`][] create async resources independent
3541cb0ef41Sopenharmony_ciof Node.js itself.
3551cb0ef41Sopenharmony_ci
3561cb0ef41Sopenharmony_ciThere is also the `PROMISE` resource type, which is used to track `Promise`
3571cb0ef41Sopenharmony_ciinstances and asynchronous work scheduled by them.
3581cb0ef41Sopenharmony_ci
3591cb0ef41Sopenharmony_ciUsers are able to define their own `type` when using the public embedder API.
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ciIt is possible to have type name collisions. Embedders are encouraged to use
3621cb0ef41Sopenharmony_ciunique prefixes, such as the npm package name, to prevent collisions when
3631cb0ef41Sopenharmony_cilistening to the hooks.
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci##### `triggerAsyncId`
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_ci`triggerAsyncId` is the `asyncId` of the resource that caused (or "triggered")
3681cb0ef41Sopenharmony_cithe new resource to initialize and that caused `init` to call. This is different
3691cb0ef41Sopenharmony_cifrom `async_hooks.executionAsyncId()` that only shows _when_ a resource was
3701cb0ef41Sopenharmony_cicreated, while `triggerAsyncId` shows _why_ a resource was created.
3711cb0ef41Sopenharmony_ci
3721cb0ef41Sopenharmony_ciThe following is a simple demonstration of `triggerAsyncId`:
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci```mjs
3751cb0ef41Sopenharmony_ciimport { createHook, executionAsyncId } from 'node:async_hooks';
3761cb0ef41Sopenharmony_ciimport { stdout } from 'node:process';
3771cb0ef41Sopenharmony_ciimport net from 'node:net';
3781cb0ef41Sopenharmony_ciimport fs from 'node:fs';
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_cicreateHook({
3811cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId) {
3821cb0ef41Sopenharmony_ci    const eid = executionAsyncId();
3831cb0ef41Sopenharmony_ci    fs.writeSync(
3841cb0ef41Sopenharmony_ci      stdout.fd,
3851cb0ef41Sopenharmony_ci      `${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
3861cb0ef41Sopenharmony_ci  },
3871cb0ef41Sopenharmony_ci}).enable();
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_cinet.createServer((conn) => {}).listen(8080);
3901cb0ef41Sopenharmony_ci```
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci```cjs
3931cb0ef41Sopenharmony_ciconst { createHook, executionAsyncId } = require('node:async_hooks');
3941cb0ef41Sopenharmony_ciconst { stdout } = require('node:process');
3951cb0ef41Sopenharmony_ciconst net = require('node:net');
3961cb0ef41Sopenharmony_ciconst fs = require('node:fs');
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_cicreateHook({
3991cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId) {
4001cb0ef41Sopenharmony_ci    const eid = executionAsyncId();
4011cb0ef41Sopenharmony_ci    fs.writeSync(
4021cb0ef41Sopenharmony_ci      stdout.fd,
4031cb0ef41Sopenharmony_ci      `${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
4041cb0ef41Sopenharmony_ci  },
4051cb0ef41Sopenharmony_ci}).enable();
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_cinet.createServer((conn) => {}).listen(8080);
4081cb0ef41Sopenharmony_ci```
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ciOutput when hitting the server with `nc localhost 8080`:
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_ci```console
4131cb0ef41Sopenharmony_ciTCPSERVERWRAP(5): trigger: 1 execution: 1
4141cb0ef41Sopenharmony_ciTCPWRAP(7): trigger: 5 execution: 0
4151cb0ef41Sopenharmony_ci```
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_ciThe `TCPSERVERWRAP` is the server which receives the connections.
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_ciThe `TCPWRAP` is the new connection from the client. When a new
4201cb0ef41Sopenharmony_ciconnection is made, the `TCPWrap` instance is immediately constructed. This
4211cb0ef41Sopenharmony_cihappens outside of any JavaScript stack. (An `executionAsyncId()` of `0` means
4221cb0ef41Sopenharmony_cithat it is being executed from C++ with no JavaScript stack above it.) With only
4231cb0ef41Sopenharmony_cithat information, it would be impossible to link resources together in
4241cb0ef41Sopenharmony_citerms of what caused them to be created, so `triggerAsyncId` is given the task
4251cb0ef41Sopenharmony_ciof propagating what resource is responsible for the new resource's existence.
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci##### `resource`
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci`resource` is an object that represents the actual async resource that has
4301cb0ef41Sopenharmony_cibeen initialized. The API to access the object may be specified by the
4311cb0ef41Sopenharmony_cicreator of the resource. Resources created by Node.js itself are internal
4321cb0ef41Sopenharmony_ciand may change at any time. Therefore no API is specified for these.
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ciIn some cases the resource object is reused for performance reasons, it is
4351cb0ef41Sopenharmony_cithus not safe to use it as a key in a `WeakMap` or add properties to it.
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci##### Asynchronous context example
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ciThe context tracking use case is covered by the stable API [`AsyncLocalStorage`][].
4401cb0ef41Sopenharmony_ciThis example only illustrates async hooks operation but [`AsyncLocalStorage`][]
4411cb0ef41Sopenharmony_cifits better to this use case.
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_ciThe following is an example with additional information about the calls to
4441cb0ef41Sopenharmony_ci`init` between the `before` and `after` calls, specifically what the
4451cb0ef41Sopenharmony_cicallback to `listen()` will look like. The output formatting is slightly more
4461cb0ef41Sopenharmony_cielaborate to make calling context easier to see.
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci```mjs
4491cb0ef41Sopenharmony_ciimport async_hooks from 'node:async_hooks';
4501cb0ef41Sopenharmony_ciimport fs from 'node:fs';
4511cb0ef41Sopenharmony_ciimport net from 'node:net';
4521cb0ef41Sopenharmony_ciimport { stdout } from 'node:process';
4531cb0ef41Sopenharmony_ciconst { fd } = stdout;
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_cilet indent = 0;
4561cb0ef41Sopenharmony_ciasync_hooks.createHook({
4571cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId) {
4581cb0ef41Sopenharmony_ci    const eid = async_hooks.executionAsyncId();
4591cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
4601cb0ef41Sopenharmony_ci    fs.writeSync(
4611cb0ef41Sopenharmony_ci      fd,
4621cb0ef41Sopenharmony_ci      `${indentStr}${type}(${asyncId}):` +
4631cb0ef41Sopenharmony_ci      ` trigger: ${triggerAsyncId} execution: ${eid}\n`);
4641cb0ef41Sopenharmony_ci  },
4651cb0ef41Sopenharmony_ci  before(asyncId) {
4661cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
4671cb0ef41Sopenharmony_ci    fs.writeSync(fd, `${indentStr}before:  ${asyncId}\n`);
4681cb0ef41Sopenharmony_ci    indent += 2;
4691cb0ef41Sopenharmony_ci  },
4701cb0ef41Sopenharmony_ci  after(asyncId) {
4711cb0ef41Sopenharmony_ci    indent -= 2;
4721cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
4731cb0ef41Sopenharmony_ci    fs.writeSync(fd, `${indentStr}after:  ${asyncId}\n`);
4741cb0ef41Sopenharmony_ci  },
4751cb0ef41Sopenharmony_ci  destroy(asyncId) {
4761cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
4771cb0ef41Sopenharmony_ci    fs.writeSync(fd, `${indentStr}destroy:  ${asyncId}\n`);
4781cb0ef41Sopenharmony_ci  },
4791cb0ef41Sopenharmony_ci}).enable();
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_cinet.createServer(() => {}).listen(8080, () => {
4821cb0ef41Sopenharmony_ci  // Let's wait 10ms before logging the server started.
4831cb0ef41Sopenharmony_ci  setTimeout(() => {
4841cb0ef41Sopenharmony_ci    console.log('>>>', async_hooks.executionAsyncId());
4851cb0ef41Sopenharmony_ci  }, 10);
4861cb0ef41Sopenharmony_ci});
4871cb0ef41Sopenharmony_ci```
4881cb0ef41Sopenharmony_ci
4891cb0ef41Sopenharmony_ci```cjs
4901cb0ef41Sopenharmony_ciconst async_hooks = require('node:async_hooks');
4911cb0ef41Sopenharmony_ciconst fs = require('node:fs');
4921cb0ef41Sopenharmony_ciconst net = require('node:net');
4931cb0ef41Sopenharmony_ciconst { fd } = process.stdout;
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_cilet indent = 0;
4961cb0ef41Sopenharmony_ciasync_hooks.createHook({
4971cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId) {
4981cb0ef41Sopenharmony_ci    const eid = async_hooks.executionAsyncId();
4991cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
5001cb0ef41Sopenharmony_ci    fs.writeSync(
5011cb0ef41Sopenharmony_ci      fd,
5021cb0ef41Sopenharmony_ci      `${indentStr}${type}(${asyncId}):` +
5031cb0ef41Sopenharmony_ci      ` trigger: ${triggerAsyncId} execution: ${eid}\n`);
5041cb0ef41Sopenharmony_ci  },
5051cb0ef41Sopenharmony_ci  before(asyncId) {
5061cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
5071cb0ef41Sopenharmony_ci    fs.writeSync(fd, `${indentStr}before:  ${asyncId}\n`);
5081cb0ef41Sopenharmony_ci    indent += 2;
5091cb0ef41Sopenharmony_ci  },
5101cb0ef41Sopenharmony_ci  after(asyncId) {
5111cb0ef41Sopenharmony_ci    indent -= 2;
5121cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
5131cb0ef41Sopenharmony_ci    fs.writeSync(fd, `${indentStr}after:  ${asyncId}\n`);
5141cb0ef41Sopenharmony_ci  },
5151cb0ef41Sopenharmony_ci  destroy(asyncId) {
5161cb0ef41Sopenharmony_ci    const indentStr = ' '.repeat(indent);
5171cb0ef41Sopenharmony_ci    fs.writeSync(fd, `${indentStr}destroy:  ${asyncId}\n`);
5181cb0ef41Sopenharmony_ci  },
5191cb0ef41Sopenharmony_ci}).enable();
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_cinet.createServer(() => {}).listen(8080, () => {
5221cb0ef41Sopenharmony_ci  // Let's wait 10ms before logging the server started.
5231cb0ef41Sopenharmony_ci  setTimeout(() => {
5241cb0ef41Sopenharmony_ci    console.log('>>>', async_hooks.executionAsyncId());
5251cb0ef41Sopenharmony_ci  }, 10);
5261cb0ef41Sopenharmony_ci});
5271cb0ef41Sopenharmony_ci```
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ciOutput from only starting the server:
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci```console
5321cb0ef41Sopenharmony_ciTCPSERVERWRAP(5): trigger: 1 execution: 1
5331cb0ef41Sopenharmony_ciTickObject(6): trigger: 5 execution: 1
5341cb0ef41Sopenharmony_cibefore:  6
5351cb0ef41Sopenharmony_ci  Timeout(7): trigger: 6 execution: 6
5361cb0ef41Sopenharmony_ciafter:   6
5371cb0ef41Sopenharmony_cidestroy: 6
5381cb0ef41Sopenharmony_cibefore:  7
5391cb0ef41Sopenharmony_ci>>> 7
5401cb0ef41Sopenharmony_ci  TickObject(8): trigger: 7 execution: 7
5411cb0ef41Sopenharmony_ciafter:   7
5421cb0ef41Sopenharmony_cibefore:  8
5431cb0ef41Sopenharmony_ciafter:   8
5441cb0ef41Sopenharmony_ci```
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_ciAs illustrated in the example, `executionAsyncId()` and `execution` each specify
5471cb0ef41Sopenharmony_cithe value of the current execution context; which is delineated by calls to
5481cb0ef41Sopenharmony_ci`before` and `after`.
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ciOnly using `execution` to graph resource allocation results in the following:
5511cb0ef41Sopenharmony_ci
5521cb0ef41Sopenharmony_ci```console
5531cb0ef41Sopenharmony_ci  root(1)
5541cb0ef41Sopenharmony_ci     ^
5551cb0ef41Sopenharmony_ci     |
5561cb0ef41Sopenharmony_ciTickObject(6)
5571cb0ef41Sopenharmony_ci     ^
5581cb0ef41Sopenharmony_ci     |
5591cb0ef41Sopenharmony_ci Timeout(7)
5601cb0ef41Sopenharmony_ci```
5611cb0ef41Sopenharmony_ci
5621cb0ef41Sopenharmony_ciThe `TCPSERVERWRAP` is not part of this graph, even though it was the reason for
5631cb0ef41Sopenharmony_ci`console.log()` being called. This is because binding to a port without a host
5641cb0ef41Sopenharmony_ciname is a _synchronous_ operation, but to maintain a completely asynchronous
5651cb0ef41Sopenharmony_ciAPI the user's callback is placed in a `process.nextTick()`. Which is why
5661cb0ef41Sopenharmony_ci`TickObject` is present in the output and is a 'parent' for `.listen()`
5671cb0ef41Sopenharmony_cicallback.
5681cb0ef41Sopenharmony_ci
5691cb0ef41Sopenharmony_ciThe graph only shows _when_ a resource was created, not _why_, so to track
5701cb0ef41Sopenharmony_cithe _why_ use `triggerAsyncId`. Which can be represented with the following
5711cb0ef41Sopenharmony_cigraph:
5721cb0ef41Sopenharmony_ci
5731cb0ef41Sopenharmony_ci```console
5741cb0ef41Sopenharmony_ci bootstrap(1)
5751cb0ef41Sopenharmony_ci     |
5761cb0ef41Sopenharmony_ci     ˅
5771cb0ef41Sopenharmony_ciTCPSERVERWRAP(5)
5781cb0ef41Sopenharmony_ci     |
5791cb0ef41Sopenharmony_ci     ˅
5801cb0ef41Sopenharmony_ci TickObject(6)
5811cb0ef41Sopenharmony_ci     |
5821cb0ef41Sopenharmony_ci     ˅
5831cb0ef41Sopenharmony_ci  Timeout(7)
5841cb0ef41Sopenharmony_ci```
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci#### `before(asyncId)`
5871cb0ef41Sopenharmony_ci
5881cb0ef41Sopenharmony_ci* `asyncId` {number}
5891cb0ef41Sopenharmony_ci
5901cb0ef41Sopenharmony_ciWhen an asynchronous operation is initiated (such as a TCP server receiving a
5911cb0ef41Sopenharmony_cinew connection) or completes (such as writing data to disk) a callback is
5921cb0ef41Sopenharmony_cicalled to notify the user. The `before` callback is called just before said
5931cb0ef41Sopenharmony_cicallback is executed. `asyncId` is the unique identifier assigned to the
5941cb0ef41Sopenharmony_ciresource about to execute the callback.
5951cb0ef41Sopenharmony_ci
5961cb0ef41Sopenharmony_ciThe `before` callback will be called 0 to N times. The `before` callback
5971cb0ef41Sopenharmony_ciwill typically be called 0 times if the asynchronous operation was cancelled
5981cb0ef41Sopenharmony_cior, for example, if no connections are received by a TCP server. Persistent
5991cb0ef41Sopenharmony_ciasynchronous resources like a TCP server will typically call the `before`
6001cb0ef41Sopenharmony_cicallback multiple times, while other operations like `fs.open()` will call
6011cb0ef41Sopenharmony_ciit only once.
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_ci#### `after(asyncId)`
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_ci* `asyncId` {number}
6061cb0ef41Sopenharmony_ci
6071cb0ef41Sopenharmony_ciCalled immediately after the callback specified in `before` is completed.
6081cb0ef41Sopenharmony_ci
6091cb0ef41Sopenharmony_ciIf an uncaught exception occurs during execution of the callback, then `after`
6101cb0ef41Sopenharmony_ciwill run _after_ the `'uncaughtException'` event is emitted or a `domain`'s
6111cb0ef41Sopenharmony_cihandler runs.
6121cb0ef41Sopenharmony_ci
6131cb0ef41Sopenharmony_ci#### `destroy(asyncId)`
6141cb0ef41Sopenharmony_ci
6151cb0ef41Sopenharmony_ci* `asyncId` {number}
6161cb0ef41Sopenharmony_ci
6171cb0ef41Sopenharmony_ciCalled after the resource corresponding to `asyncId` is destroyed. It is also
6181cb0ef41Sopenharmony_cicalled asynchronously from the embedder API `emitDestroy()`.
6191cb0ef41Sopenharmony_ci
6201cb0ef41Sopenharmony_ciSome resources depend on garbage collection for cleanup, so if a reference is
6211cb0ef41Sopenharmony_cimade to the `resource` object passed to `init` it is possible that `destroy`
6221cb0ef41Sopenharmony_ciwill never be called, causing a memory leak in the application. If the resource
6231cb0ef41Sopenharmony_cidoes not depend on garbage collection, then this will not be an issue.
6241cb0ef41Sopenharmony_ci
6251cb0ef41Sopenharmony_ciUsing the destroy hook results in additional overhead because it enables
6261cb0ef41Sopenharmony_citracking of `Promise` instances via the garbage collector.
6271cb0ef41Sopenharmony_ci
6281cb0ef41Sopenharmony_ci#### `promiseResolve(asyncId)`
6291cb0ef41Sopenharmony_ci
6301cb0ef41Sopenharmony_ci<!-- YAML
6311cb0ef41Sopenharmony_ciadded: v8.6.0
6321cb0ef41Sopenharmony_ci-->
6331cb0ef41Sopenharmony_ci
6341cb0ef41Sopenharmony_ci* `asyncId` {number}
6351cb0ef41Sopenharmony_ci
6361cb0ef41Sopenharmony_ciCalled when the `resolve` function passed to the `Promise` constructor is
6371cb0ef41Sopenharmony_ciinvoked (either directly or through other means of resolving a promise).
6381cb0ef41Sopenharmony_ci
6391cb0ef41Sopenharmony_ci`resolve()` does not do any observable synchronous work.
6401cb0ef41Sopenharmony_ci
6411cb0ef41Sopenharmony_ciThe `Promise` is not necessarily fulfilled or rejected at this point if the
6421cb0ef41Sopenharmony_ci`Promise` was resolved by assuming the state of another `Promise`.
6431cb0ef41Sopenharmony_ci
6441cb0ef41Sopenharmony_ci```js
6451cb0ef41Sopenharmony_cinew Promise((resolve) => resolve(true)).then((a) => {});
6461cb0ef41Sopenharmony_ci```
6471cb0ef41Sopenharmony_ci
6481cb0ef41Sopenharmony_cicalls the following callbacks:
6491cb0ef41Sopenharmony_ci
6501cb0ef41Sopenharmony_ci```text
6511cb0ef41Sopenharmony_ciinit for PROMISE with id 5, trigger id: 1
6521cb0ef41Sopenharmony_ci  promise resolve 5      # corresponds to resolve(true)
6531cb0ef41Sopenharmony_ciinit for PROMISE with id 6, trigger id: 5  # the Promise returned by then()
6541cb0ef41Sopenharmony_ci  before 6               # the then() callback is entered
6551cb0ef41Sopenharmony_ci  promise resolve 6      # the then() callback resolves the promise by returning
6561cb0ef41Sopenharmony_ci  after 6
6571cb0ef41Sopenharmony_ci```
6581cb0ef41Sopenharmony_ci
6591cb0ef41Sopenharmony_ci### `async_hooks.executionAsyncResource()`
6601cb0ef41Sopenharmony_ci
6611cb0ef41Sopenharmony_ci<!-- YAML
6621cb0ef41Sopenharmony_ciadded:
6631cb0ef41Sopenharmony_ci - v13.9.0
6641cb0ef41Sopenharmony_ci - v12.17.0
6651cb0ef41Sopenharmony_ci-->
6661cb0ef41Sopenharmony_ci
6671cb0ef41Sopenharmony_ci* Returns: {Object} The resource representing the current execution.
6681cb0ef41Sopenharmony_ci  Useful to store data within the resource.
6691cb0ef41Sopenharmony_ci
6701cb0ef41Sopenharmony_ciResource objects returned by `executionAsyncResource()` are most often internal
6711cb0ef41Sopenharmony_ciNode.js handle objects with undocumented APIs. Using any functions or properties
6721cb0ef41Sopenharmony_cion the object is likely to crash your application and should be avoided.
6731cb0ef41Sopenharmony_ci
6741cb0ef41Sopenharmony_ciUsing `executionAsyncResource()` in the top-level execution context will
6751cb0ef41Sopenharmony_cireturn an empty object as there is no handle or request object to use,
6761cb0ef41Sopenharmony_cibut having an object representing the top-level can be helpful.
6771cb0ef41Sopenharmony_ci
6781cb0ef41Sopenharmony_ci```mjs
6791cb0ef41Sopenharmony_ciimport { open } from 'node:fs';
6801cb0ef41Sopenharmony_ciimport { executionAsyncId, executionAsyncResource } from 'node:async_hooks';
6811cb0ef41Sopenharmony_ci
6821cb0ef41Sopenharmony_ciconsole.log(executionAsyncId(), executionAsyncResource());  // 1 {}
6831cb0ef41Sopenharmony_ciopen(new URL(import.meta.url), 'r', (err, fd) => {
6841cb0ef41Sopenharmony_ci  console.log(executionAsyncId(), executionAsyncResource());  // 7 FSReqWrap
6851cb0ef41Sopenharmony_ci});
6861cb0ef41Sopenharmony_ci```
6871cb0ef41Sopenharmony_ci
6881cb0ef41Sopenharmony_ci```cjs
6891cb0ef41Sopenharmony_ciconst { open } = require('node:fs');
6901cb0ef41Sopenharmony_ciconst { executionAsyncId, executionAsyncResource } = require('node:async_hooks');
6911cb0ef41Sopenharmony_ci
6921cb0ef41Sopenharmony_ciconsole.log(executionAsyncId(), executionAsyncResource());  // 1 {}
6931cb0ef41Sopenharmony_ciopen(__filename, 'r', (err, fd) => {
6941cb0ef41Sopenharmony_ci  console.log(executionAsyncId(), executionAsyncResource());  // 7 FSReqWrap
6951cb0ef41Sopenharmony_ci});
6961cb0ef41Sopenharmony_ci```
6971cb0ef41Sopenharmony_ci
6981cb0ef41Sopenharmony_ciThis can be used to implement continuation local storage without the
6991cb0ef41Sopenharmony_ciuse of a tracking `Map` to store the metadata:
7001cb0ef41Sopenharmony_ci
7011cb0ef41Sopenharmony_ci```mjs
7021cb0ef41Sopenharmony_ciimport { createServer } from 'node:http';
7031cb0ef41Sopenharmony_ciimport {
7041cb0ef41Sopenharmony_ci  executionAsyncId,
7051cb0ef41Sopenharmony_ci  executionAsyncResource,
7061cb0ef41Sopenharmony_ci  createHook,
7071cb0ef41Sopenharmony_ci} from 'async_hooks';
7081cb0ef41Sopenharmony_ciconst sym = Symbol('state'); // Private symbol to avoid pollution
7091cb0ef41Sopenharmony_ci
7101cb0ef41Sopenharmony_cicreateHook({
7111cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId, resource) {
7121cb0ef41Sopenharmony_ci    const cr = executionAsyncResource();
7131cb0ef41Sopenharmony_ci    if (cr) {
7141cb0ef41Sopenharmony_ci      resource[sym] = cr[sym];
7151cb0ef41Sopenharmony_ci    }
7161cb0ef41Sopenharmony_ci  },
7171cb0ef41Sopenharmony_ci}).enable();
7181cb0ef41Sopenharmony_ci
7191cb0ef41Sopenharmony_ciconst server = createServer((req, res) => {
7201cb0ef41Sopenharmony_ci  executionAsyncResource()[sym] = { state: req.url };
7211cb0ef41Sopenharmony_ci  setTimeout(function() {
7221cb0ef41Sopenharmony_ci    res.end(JSON.stringify(executionAsyncResource()[sym]));
7231cb0ef41Sopenharmony_ci  }, 100);
7241cb0ef41Sopenharmony_ci}).listen(3000);
7251cb0ef41Sopenharmony_ci```
7261cb0ef41Sopenharmony_ci
7271cb0ef41Sopenharmony_ci```cjs
7281cb0ef41Sopenharmony_ciconst { createServer } = require('node:http');
7291cb0ef41Sopenharmony_ciconst {
7301cb0ef41Sopenharmony_ci  executionAsyncId,
7311cb0ef41Sopenharmony_ci  executionAsyncResource,
7321cb0ef41Sopenharmony_ci  createHook,
7331cb0ef41Sopenharmony_ci} = require('node:async_hooks');
7341cb0ef41Sopenharmony_ciconst sym = Symbol('state'); // Private symbol to avoid pollution
7351cb0ef41Sopenharmony_ci
7361cb0ef41Sopenharmony_cicreateHook({
7371cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId, resource) {
7381cb0ef41Sopenharmony_ci    const cr = executionAsyncResource();
7391cb0ef41Sopenharmony_ci    if (cr) {
7401cb0ef41Sopenharmony_ci      resource[sym] = cr[sym];
7411cb0ef41Sopenharmony_ci    }
7421cb0ef41Sopenharmony_ci  },
7431cb0ef41Sopenharmony_ci}).enable();
7441cb0ef41Sopenharmony_ci
7451cb0ef41Sopenharmony_ciconst server = createServer((req, res) => {
7461cb0ef41Sopenharmony_ci  executionAsyncResource()[sym] = { state: req.url };
7471cb0ef41Sopenharmony_ci  setTimeout(function() {
7481cb0ef41Sopenharmony_ci    res.end(JSON.stringify(executionAsyncResource()[sym]));
7491cb0ef41Sopenharmony_ci  }, 100);
7501cb0ef41Sopenharmony_ci}).listen(3000);
7511cb0ef41Sopenharmony_ci```
7521cb0ef41Sopenharmony_ci
7531cb0ef41Sopenharmony_ci### `async_hooks.executionAsyncId()`
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_ci<!-- YAML
7561cb0ef41Sopenharmony_ciadded: v8.1.0
7571cb0ef41Sopenharmony_cichanges:
7581cb0ef41Sopenharmony_ci  - version: v8.2.0
7591cb0ef41Sopenharmony_ci    pr-url: https://github.com/nodejs/node/pull/13490
7601cb0ef41Sopenharmony_ci    description: Renamed from `currentId`.
7611cb0ef41Sopenharmony_ci-->
7621cb0ef41Sopenharmony_ci
7631cb0ef41Sopenharmony_ci* Returns: {number} The `asyncId` of the current execution context. Useful to
7641cb0ef41Sopenharmony_ci  track when something calls.
7651cb0ef41Sopenharmony_ci
7661cb0ef41Sopenharmony_ci```mjs
7671cb0ef41Sopenharmony_ciimport { executionAsyncId } from 'node:async_hooks';
7681cb0ef41Sopenharmony_ciimport fs from 'node:fs';
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_ciconsole.log(executionAsyncId());  // 1 - bootstrap
7711cb0ef41Sopenharmony_ciconst path = '.';
7721cb0ef41Sopenharmony_cifs.open(path, 'r', (err, fd) => {
7731cb0ef41Sopenharmony_ci  console.log(executionAsyncId());  // 6 - open()
7741cb0ef41Sopenharmony_ci});
7751cb0ef41Sopenharmony_ci```
7761cb0ef41Sopenharmony_ci
7771cb0ef41Sopenharmony_ci```cjs
7781cb0ef41Sopenharmony_ciconst async_hooks = require('node:async_hooks');
7791cb0ef41Sopenharmony_ciconst fs = require('node:fs');
7801cb0ef41Sopenharmony_ci
7811cb0ef41Sopenharmony_ciconsole.log(async_hooks.executionAsyncId());  // 1 - bootstrap
7821cb0ef41Sopenharmony_ciconst path = '.';
7831cb0ef41Sopenharmony_cifs.open(path, 'r', (err, fd) => {
7841cb0ef41Sopenharmony_ci  console.log(async_hooks.executionAsyncId());  // 6 - open()
7851cb0ef41Sopenharmony_ci});
7861cb0ef41Sopenharmony_ci```
7871cb0ef41Sopenharmony_ci
7881cb0ef41Sopenharmony_ciThe ID returned from `executionAsyncId()` is related to execution timing, not
7891cb0ef41Sopenharmony_cicausality (which is covered by `triggerAsyncId()`):
7901cb0ef41Sopenharmony_ci
7911cb0ef41Sopenharmony_ci```js
7921cb0ef41Sopenharmony_ciconst server = net.createServer((conn) => {
7931cb0ef41Sopenharmony_ci  // Returns the ID of the server, not of the new connection, because the
7941cb0ef41Sopenharmony_ci  // callback runs in the execution scope of the server's MakeCallback().
7951cb0ef41Sopenharmony_ci  async_hooks.executionAsyncId();
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_ci}).listen(port, () => {
7981cb0ef41Sopenharmony_ci  // Returns the ID of a TickObject (process.nextTick()) because all
7991cb0ef41Sopenharmony_ci  // callbacks passed to .listen() are wrapped in a nextTick().
8001cb0ef41Sopenharmony_ci  async_hooks.executionAsyncId();
8011cb0ef41Sopenharmony_ci});
8021cb0ef41Sopenharmony_ci```
8031cb0ef41Sopenharmony_ci
8041cb0ef41Sopenharmony_ciPromise contexts may not get precise `executionAsyncIds` by default.
8051cb0ef41Sopenharmony_ciSee the section on [promise execution tracking][].
8061cb0ef41Sopenharmony_ci
8071cb0ef41Sopenharmony_ci### `async_hooks.triggerAsyncId()`
8081cb0ef41Sopenharmony_ci
8091cb0ef41Sopenharmony_ci* Returns: {number} The ID of the resource responsible for calling the callback
8101cb0ef41Sopenharmony_ci  that is currently being executed.
8111cb0ef41Sopenharmony_ci
8121cb0ef41Sopenharmony_ci```js
8131cb0ef41Sopenharmony_ciconst server = net.createServer((conn) => {
8141cb0ef41Sopenharmony_ci  // The resource that caused (or triggered) this callback to be called
8151cb0ef41Sopenharmony_ci  // was that of the new connection. Thus the return value of triggerAsyncId()
8161cb0ef41Sopenharmony_ci  // is the asyncId of "conn".
8171cb0ef41Sopenharmony_ci  async_hooks.triggerAsyncId();
8181cb0ef41Sopenharmony_ci
8191cb0ef41Sopenharmony_ci}).listen(port, () => {
8201cb0ef41Sopenharmony_ci  // Even though all callbacks passed to .listen() are wrapped in a nextTick()
8211cb0ef41Sopenharmony_ci  // the callback itself exists because the call to the server's .listen()
8221cb0ef41Sopenharmony_ci  // was made. So the return value would be the ID of the server.
8231cb0ef41Sopenharmony_ci  async_hooks.triggerAsyncId();
8241cb0ef41Sopenharmony_ci});
8251cb0ef41Sopenharmony_ci```
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_ciPromise contexts may not get valid `triggerAsyncId`s by default. See
8281cb0ef41Sopenharmony_cithe section on [promise execution tracking][].
8291cb0ef41Sopenharmony_ci
8301cb0ef41Sopenharmony_ci### `async_hooks.asyncWrapProviders`
8311cb0ef41Sopenharmony_ci
8321cb0ef41Sopenharmony_ci<!-- YAML
8331cb0ef41Sopenharmony_ciadded:
8341cb0ef41Sopenharmony_ci  - v17.2.0
8351cb0ef41Sopenharmony_ci  - v16.14.0
8361cb0ef41Sopenharmony_ci-->
8371cb0ef41Sopenharmony_ci
8381cb0ef41Sopenharmony_ci* Returns: A map of provider types to the corresponding numeric id.
8391cb0ef41Sopenharmony_ci  This map contains all the event types that might be emitted by the `async_hooks.init()` event.
8401cb0ef41Sopenharmony_ci
8411cb0ef41Sopenharmony_ciThis feature suppresses the deprecated usage of `process.binding('async_wrap').Providers`.
8421cb0ef41Sopenharmony_ciSee: [DEP0111][]
8431cb0ef41Sopenharmony_ci
8441cb0ef41Sopenharmony_ci## Promise execution tracking
8451cb0ef41Sopenharmony_ci
8461cb0ef41Sopenharmony_ciBy default, promise executions are not assigned `asyncId`s due to the relatively
8471cb0ef41Sopenharmony_ciexpensive nature of the [promise introspection API][PromiseHooks] provided by
8481cb0ef41Sopenharmony_ciV8. This means that programs using promises or `async`/`await` will not get
8491cb0ef41Sopenharmony_cicorrect execution and trigger ids for promise callback contexts by default.
8501cb0ef41Sopenharmony_ci
8511cb0ef41Sopenharmony_ci```mjs
8521cb0ef41Sopenharmony_ciimport { executionAsyncId, triggerAsyncId } from 'node:async_hooks';
8531cb0ef41Sopenharmony_ci
8541cb0ef41Sopenharmony_ciPromise.resolve(1729).then(() => {
8551cb0ef41Sopenharmony_ci  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
8561cb0ef41Sopenharmony_ci});
8571cb0ef41Sopenharmony_ci// produces:
8581cb0ef41Sopenharmony_ci// eid 1 tid 0
8591cb0ef41Sopenharmony_ci```
8601cb0ef41Sopenharmony_ci
8611cb0ef41Sopenharmony_ci```cjs
8621cb0ef41Sopenharmony_ciconst { executionAsyncId, triggerAsyncId } = require('node:async_hooks');
8631cb0ef41Sopenharmony_ci
8641cb0ef41Sopenharmony_ciPromise.resolve(1729).then(() => {
8651cb0ef41Sopenharmony_ci  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
8661cb0ef41Sopenharmony_ci});
8671cb0ef41Sopenharmony_ci// produces:
8681cb0ef41Sopenharmony_ci// eid 1 tid 0
8691cb0ef41Sopenharmony_ci```
8701cb0ef41Sopenharmony_ci
8711cb0ef41Sopenharmony_ciObserve that the `then()` callback claims to have executed in the context of the
8721cb0ef41Sopenharmony_ciouter scope even though there was an asynchronous hop involved. Also,
8731cb0ef41Sopenharmony_cithe `triggerAsyncId` value is `0`, which means that we are missing context about
8741cb0ef41Sopenharmony_cithe resource that caused (triggered) the `then()` callback to be executed.
8751cb0ef41Sopenharmony_ci
8761cb0ef41Sopenharmony_ciInstalling async hooks via `async_hooks.createHook` enables promise execution
8771cb0ef41Sopenharmony_citracking:
8781cb0ef41Sopenharmony_ci
8791cb0ef41Sopenharmony_ci```mjs
8801cb0ef41Sopenharmony_ciimport { createHook, executionAsyncId, triggerAsyncId } from 'node:async_hooks';
8811cb0ef41Sopenharmony_cicreateHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
8821cb0ef41Sopenharmony_ciPromise.resolve(1729).then(() => {
8831cb0ef41Sopenharmony_ci  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
8841cb0ef41Sopenharmony_ci});
8851cb0ef41Sopenharmony_ci// produces:
8861cb0ef41Sopenharmony_ci// eid 7 tid 6
8871cb0ef41Sopenharmony_ci```
8881cb0ef41Sopenharmony_ci
8891cb0ef41Sopenharmony_ci```cjs
8901cb0ef41Sopenharmony_ciconst { createHook, executionAsyncId, triggerAsyncId } = require('node:async_hooks');
8911cb0ef41Sopenharmony_ci
8921cb0ef41Sopenharmony_cicreateHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
8931cb0ef41Sopenharmony_ciPromise.resolve(1729).then(() => {
8941cb0ef41Sopenharmony_ci  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
8951cb0ef41Sopenharmony_ci});
8961cb0ef41Sopenharmony_ci// produces:
8971cb0ef41Sopenharmony_ci// eid 7 tid 6
8981cb0ef41Sopenharmony_ci```
8991cb0ef41Sopenharmony_ci
9001cb0ef41Sopenharmony_ciIn this example, adding any actual hook function enabled the tracking of
9011cb0ef41Sopenharmony_cipromises. There are two promises in the example above; the promise created by
9021cb0ef41Sopenharmony_ci`Promise.resolve()` and the promise returned by the call to `then()`. In the
9031cb0ef41Sopenharmony_ciexample above, the first promise got the `asyncId` `6` and the latter got
9041cb0ef41Sopenharmony_ci`asyncId` `7`. During the execution of the `then()` callback, we are executing
9051cb0ef41Sopenharmony_ciin the context of promise with `asyncId` `7`. This promise was triggered by
9061cb0ef41Sopenharmony_ciasync resource `6`.
9071cb0ef41Sopenharmony_ci
9081cb0ef41Sopenharmony_ciAnother subtlety with promises is that `before` and `after` callbacks are run
9091cb0ef41Sopenharmony_cionly on chained promises. That means promises not created by `then()`/`catch()`
9101cb0ef41Sopenharmony_ciwill not have the `before` and `after` callbacks fired on them. For more details
9111cb0ef41Sopenharmony_cisee the details of the V8 [PromiseHooks][] API.
9121cb0ef41Sopenharmony_ci
9131cb0ef41Sopenharmony_ci## JavaScript embedder API
9141cb0ef41Sopenharmony_ci
9151cb0ef41Sopenharmony_ciLibrary developers that handle their own asynchronous resources performing tasks
9161cb0ef41Sopenharmony_cilike I/O, connection pooling, or managing callback queues may use the
9171cb0ef41Sopenharmony_ci`AsyncResource` JavaScript API so that all the appropriate callbacks are called.
9181cb0ef41Sopenharmony_ci
9191cb0ef41Sopenharmony_ci### Class: `AsyncResource`
9201cb0ef41Sopenharmony_ci
9211cb0ef41Sopenharmony_ciThe documentation for this class has moved [`AsyncResource`][].
9221cb0ef41Sopenharmony_ci
9231cb0ef41Sopenharmony_ci## Class: `AsyncLocalStorage`
9241cb0ef41Sopenharmony_ci
9251cb0ef41Sopenharmony_ciThe documentation for this class has moved [`AsyncLocalStorage`][].
9261cb0ef41Sopenharmony_ci
9271cb0ef41Sopenharmony_ci[DEP0111]: deprecations.md#dep0111-processbinding
9281cb0ef41Sopenharmony_ci[Diagnostics Channel]: diagnostics_channel.md
9291cb0ef41Sopenharmony_ci[Hook Callbacks]: #hook-callbacks
9301cb0ef41Sopenharmony_ci[PromiseHooks]: https://docs.google.com/document/d/1rda3yKGHimKIhg5YeoAmCOtyURgsbTH_qaYR79FELlk/edit
9311cb0ef41Sopenharmony_ci[`AsyncHook`]: #class-asynchook
9321cb0ef41Sopenharmony_ci[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage
9331cb0ef41Sopenharmony_ci[`AsyncResource`]: async_context.md#class-asyncresource
9341cb0ef41Sopenharmony_ci[`Worker`]: worker_threads.md#class-worker
9351cb0ef41Sopenharmony_ci[`after` callback]: #afterasyncid
9361cb0ef41Sopenharmony_ci[`before` callback]: #beforeasyncid
9371cb0ef41Sopenharmony_ci[`createHook`]: #async_hookscreatehookcallbacks
9381cb0ef41Sopenharmony_ci[`destroy` callback]: #destroyasyncid
9391cb0ef41Sopenharmony_ci[`executionAsyncResource`]: #async_hooksexecutionasyncresource
9401cb0ef41Sopenharmony_ci[`init` callback]: #initasyncid-type-triggerasyncid-resource
9411cb0ef41Sopenharmony_ci[`process.getActiveResourcesInfo()`]: process.md#processgetactiveresourcesinfo
9421cb0ef41Sopenharmony_ci[`promiseResolve` callback]: #promiseresolveasyncid
9431cb0ef41Sopenharmony_ci[promise execution tracking]: #promise-execution-tracking
944