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