Async hooks | Node.js v26.8.2 Documentation
https://nodejs.org/api/async_hooks.html • 224 KB fetched
Open original page
Async hooks | Node.js v26.8.2 Documentation Skip to content
Node.js
* About this documentation
* Usage and example
* Assertion testing
* Asynchronous context tracking
* Async hooks
* Buffer
* C++ addons
* C/C++ addons with Node-API
* C++ embedder API
* Child processes
* Cluster
* Command-line options
* Console
* Crypto
* Debugger
* Deprecated APIs
* Diagnostics Channel
* DNS
* Domain
* Environment Variables
* Errors
* Events
* File system
* FFI
* Globals
* HTTP
* HTTP/2
* HTTPS
* Inspector
* Internationalization
* Iterable Streams API
* Modules: CommonJS modules
* Modules: ECMAScript modules
* Modules: node:module API
* Modules: Packages
* Modules: TypeScript
* Net
* OS
* Path
* Performance hooks
* Permissions
* Process
* Punycode
* Query strings
* Readline
* REPL
* Report
* Single executable applications
* SQLite
* Stream
* String decoder
* Test runner
* Timers
* TLS/SSL
* Trace events
* TTY
* UDP/datagram
* URL
* Utilities
* V8
* Virtual File System
* VM
* WASI
* Web Crypto API
* Web Streams API
* Worker threads
* Zlib
*
Code repository and issue tracker
Node.js v26.8.2 documentation
* Node.js v26.8.2
* Table of contents
* Async hooks
* Terminology
* Overview
* async_hooks.createHook(options)
* Error handling
* Printing in AsyncHook callbacks
* Class: AsyncHook
* asyncHook.enable()
* asyncHook.disable()
* Hook callbacks
* init(asyncId, type, triggerAsyncId, resource)
* type
* triggerAsyncId
* resource
* Asynchronous context example
* before(asyncId)
* after(asyncId)
* destroy(asyncId)
* promiseResolve(asyncId)
* async_hooks.executionAsyncResource()
* async_hooks.executionAsyncId()
* async_hooks.triggerAsyncId()
* async_hooks.asyncWrapProviders
* Promise execution tracking
* Disabling promise execution tracking
* JavaScript embedder API
* Class: AsyncResource
* Class: AsyncLocalStorage
* Index
* Index
* About this documentation
* Usage and example
* Assertion testing
* Asynchronous context tracking
* Async hooks
* Buffer
* C++ addons
* C/C++ addons with Node-API
* C++ embedder API
* Child processes
* Cluster
* Command-line options
* Console
* Crypto
* Debugger
* Deprecated APIs
* Diagnostics Channel
* DNS
* Domain
* Environment Variables
* Errors
* Events
* File system
* FFI
* Globals
* HTTP
* HTTP/2
* HTTPS
* Inspector
* Internationalization
* Iterable Streams API
* Modules: CommonJS modules
* Modules: ECMAScript modules
* Modules: node:module API
* Modules: Packages
* Modules: TypeScript
* Net
* OS
* Path
* Performance hooks
* Permissions
* Process
* Punycode
* Query strings
* Readline
* REPL
* Report
* Single executable applications
* SQLite
* Stream
* String decoder
* Test runner
* Timers
* TLS/SSL
* Trace events
* TTY
* UDP/datagram
* URL
* Utilities
* V8
* Virtual File System
* VM
* WASI
* Web Crypto API
* Web Streams API
* Worker threads
* Zlib
* Other versions
* 26.x
* 25.x
* 24.x LTS
* 23.x
* 22.x LTS
* 21.x
* 20.x
* 19.x
* 18.x
* 17.x
* 16.x
* 15.x
* 14.x
* 13.x
* 12.x
* 11.x
* 10.x
* 9.x
* 8.x
*
Options
*
View on single page
*
View as JSON
* Edit on GitHub
Table of contents
* Async hooks
* Terminology
* Overview
* async_hooks.createHook(options)
* Error handling
* Printing in AsyncHook callbacks
* Class: AsyncHook
* asyncHook.enable()
* asyncHook.disable()
* Hook callbacks
* init(asyncId, type, triggerAsyncId, resource)
* type
* triggerAsyncId
* resource
* Asynchronous context example
* before(asyncId)
* after(asyncId)
* destroy(asyncId)
* promiseResolve(asyncId)
* async_hooks.executionAsyncResource()
* async_hooks.executionAsyncId()
* async_hooks.triggerAsyncId()
* async_hooks.asyncWrapProviders
* Promise execution tracking
* Disabling promise execution tracking
* JavaScript embedder API
* Class: AsyncResource
* Class: AsyncLocalStorage
Async hooks #
Source Code: lib/async_hooks.js
Stability: 1 - Experimental. Please migrate away from this API, if you can.
We do not recommend using the createHook , AsyncHook , and
executionAsyncResource APIs as they have usability issues, safety risks,
and performance implications. Async context tracking use cases are better
served by the stable AsyncLocalStorage API. If you have a use case for
createHook , AsyncHook , or executionAsyncResource beyond the context
tracking need solved by AsyncLocalStorage or diagnostics data currently
provided by Diagnostics Channel , please open an issue at
https://github.com/nodejs/node/issues describing your use case so we can
create a more purpose-focused API.
We strongly discourage the use of the async_hooks API.
Other APIs that can cover most of its use cases include:
* AsyncLocalStorage tracks async context
* process.getActiveResourcesInfo() tracks active resources
The node:async_hooks module provides an API to track asynchronous resources.
It can be accessed using: import async_hooks from 'node:async_hooks' ;
const async_hooks = require ( 'node:async_hooks' ) ;
javascript copy
Terminology #
An asynchronous resource represents an object with an associated callback.
This callback may be called multiple times, such as the 'connection'
event in net.createServer() , or just a single time like in fs.open() .
A resource can also be closed before the callback is called. AsyncHook does
not explicitly distinguish between these different cases but will represent them
as the abstract concept that is a resource. If Worker s are used, each thread has an independent async_hooks
interface, and each thread will use a new set of async IDs.
Overview #
Following is a simple overview of the public API. import async_hooks from 'node:async_hooks' ;
// Return the ID of the current execution context.
const eid = async_hooks . executionAsyncId () ;
// Return the ID of the handle responsible for triggering the callback of the
// current execution scope to call.
const tid = async_hooks . triggerAsyncId () ;
// Create a new AsyncHook instance. All of these callbacks are optional.
const asyncHook =
async_hooks . createHook ( { init , before , after , destroy , promiseResolve } ) ;
// Allow callbacks of this AsyncHook instance to call. This is not an implicit
// action after running the constructor, and must be explicitly run to begin
// executing callbacks.
asyncHook . enable () ;
// Disable listening for new asynchronous events.
asyncHook . disable () ;
//
// The following are the callbacks that can be passed to createHook().
//
// init() is called during object construction. The resource may not have
// completed construction when this callback runs. Therefore, all fields of the
// resource referenced by "asyncId" may not have been populated.
function init ( asyncId , type , triggerAsyncId , resource ) { }
// before() is called just before the resource's callback is called. It can be
// called 0-N times for handles (such as TCPWrap), and will be called exactly 1
// time for requests (such as FSReqCallback).
function before ( asyncId ) { }
// after() is called just after the resource's callback has finished.
function after ( asyncId ) { }
// destroy() is called when the resource is destroyed.
function destroy ( asyncId ) { }
// promiseResolve() is called only for promise resources, when the
// resolve() function passed to the Promise constructor is invoked
// (either directly or through other means of resolving a promise).
function promiseResolve ( asyncId ) { }
const async_hooks = require ( 'node:async_hooks' ) ;
// Return the ID of the current execution context.
const eid = async_hooks . executionAsyncId () ;
// Return the ID of the handle responsible for triggering the callback of the
// current execution scope to call.
const tid = async_hooks . triggerAsyncId () ;
// Create a new AsyncHook instance. All of these callbacks are optional.
const asyncHook =
async_hooks . createHook ( { init , before , after , destroy , promiseResolve } ) ;
// Allow callbacks of this AsyncHook instance to call. This is not an implicit
// action after running the constructor, and must be explicitly run to begin
// executing callbacks.
asyncHook . enable () ;
// Disable listening for new asynchronous events.
asyncHook . disable () ;
//
// The following are the callbacks that can be passed to createHook().
//
// init() is called during object construction. The resource may not have
// completed construction when this callback runs. Therefore, all fields of the
// resource referenced by "asyncId" may not have been populated.
function init ( asyncId , type , triggerAsyncId , resource ) { }
// before() is called just before the resource's callback is called. It can be
// called 0-N times for handles (such as TCPWrap), and will be called exactly 1
// time for requests (such as FSReqCallback).
function before ( asyncId ) { }
// after() is called just after the resource's callback has finished.
function after ( asyncId ) { }
// destroy() is called when the resource is destroyed.
function destroy ( asyncId ) { }
// promiseResolve() is called only for promise resources, when the
// resolve() function passed to the Promise constructor is invoked
// (either directly or through other means of resolving a promise).
function promiseResolve ( asyncId ) { }
javascript copy
async_hooks.createHook(options) #
Added in: v8.1.0
* options <Object> The Hook Callbacks to register
* init <Function> The init callback .
* before <Function> The before callback .
* after <Function> The after callback .
* destroy <Function> The destroy callback .
* promiseResolve <Function> The promiseResolve callback .
* trackPromises <boolean> Whether the hook should track Promise s. Cannot be false if
promiseResolve is set. Default : true .
* Returns: <AsyncHook> Instance used for disabling and enabling hooks
Registers functions to be called for different lifetime events of each async
operation. The callbacks init() / before() / after() / destroy() are called for the
respective asynchronous event during a resource's lifetime. All callbacks are optional. For example, if only resource cleanup needs to
be tracked, then only the destroy callback needs to be passed. The
specifics of all functions that can be passed to callbacks is in the
Hook Callbacks section. import { createHook } from 'node:async_hooks' ;
const asyncHook = createHook ( {
init ( asyncId , type , triggerAsyncId , resource ) { },
destroy ( asyncId ) { },
} ) ;
const async_hooks = require ( 'node:async_hooks' ) ;
const asyncHook = async_hooks . createHook ( {
init ( asyncId , type , triggerAsyncId , resource ) { },
destroy ( asyncId ) { },
} ) ;
javascript copy
The callbacks will be inherited via the prototype chain: class MyAsyncCallbacks {
init ( asyncId , type , triggerAsyncId , resource ) { }
destroy ( asyncId ) {}
}
class MyAddedCallbacks extends MyAsyncCallbacks {
before ( asyncId ) { }
after ( asyncId ) { }
}
const asyncHook = async_hooks . createHook ( new MyAddedCallbacks ()) ;
js copy
Because promises are asynchronous resources whose lifecycle is tracked
via the async hooks mechanism, the init() , before() , after() , and
destroy() callbacks must not be async functions that return promises.
Error handling #
If any AsyncHook callbacks throw, the application will print the stack trace
and exit. The exit path does follow that of an uncaught exception, but
all 'uncaughtException' listeners are removed, thus forcing the process to
exit. The 'exit' callbacks will still be called unless the application is run
with --abort-on-uncaught-exception , in which case a stack trace will be
printed and the application exits, leaving a core file. The reason for this error handling behavior is that these callbacks are running
at potentially volatile points in an object's lifetime, for example during
class construction and destruction. Because of this, it is deemed necessary to
bring down the process quickly in order to prevent an unintentional abort in the
future. This is subject to change in the future if a comprehensive analysis is
performed to ensure an exception can follow the normal control flow without
unintentional side effects.
Printing in AsyncHook callbacks #
Because printing to the console is an asynchronous operation, console.log()
will cause AsyncHook callbacks to be called. Using console.log() or
similar asynchronous operations inside an AsyncHook callback function will
cause an infinite recursion. An easy solution to this when debugging is to use a
synchronous logging operation such as fs.writeFileSync(file, msg, flag) .
This will print to the file and will not invoke AsyncHook recursively because
it is synchronous. import { writeFileSync } from 'node:fs' ;
import { format } from 'node:util' ;
function debug ( ... args ) {
// Use a function like this one when debugging inside an AsyncHook callback
writeFileSync ( 'log.out' , ` ${ format ( ... args ) } \n ` , { flag : 'a' } ) ;
}
const fs = require ( 'node:fs' ) ;
const util = require ( 'node:util' ) ;
function debug ( ... args ) {
// Use a function like this one when debugging inside an AsyncHook callback
fs . writeFileSync ( 'log.out' , ` ${ util . format ( ... args ) } \n ` , { flag : 'a' } ) ;
}
javascript copy
If an asynchronous operation is needed for logging, it is possible to keep
track of what caused the asynchronous operation using the information
provided by AsyncHook itself. The logging should then be skipped when
it was the logging itself that caused the AsyncHook callback to be called. By
doing this, the otherwise infinite recursion is broken.
Class: AsyncHook #
The class AsyncHook exposes an interface for tracking lifetime events
of asynchronous operations.
asyncHook.enable() #
* Returns: <AsyncHook> A reference to asyncHook .
Enable the callbacks for a given AsyncHook instance. If no callbacks are
provided, enabling is a no-op. The AsyncHook instance is disabled by default. If the AsyncHook instance
should be enabled immediately after creation, the following pattern can be used. import { createHook } from 'node:async_hooks' ;
const hook = createHook (callbacks) . enable () ;
const async_hooks = require ( 'node:async_hooks' ) ;
const hook = async_hooks . createHook (callbacks) . enable () ;
javascript copy
asyncHook.disable() #
* Returns: <AsyncHook> A reference to asyncHook .
Disable the callbacks for a given AsyncHook instance from the global pool of
AsyncHook callbacks to be executed. Once a hook has been disabled it will not
be called again until enabled. For API consistency disable() also returns the AsyncHook instance.
Hook callbacks #
Key events in the lifetime of asynchronous events have been categorized into
four areas: instantiation, before/after the callback is called, and when the
instance is destroyed.
init(asyncId, type, triggerAsyncId, resource) #
* asyncId <number> A unique ID for the async resource.
* type <string> The type of the async resource.
* triggerAsyncId <number> The unique ID of the async resource in whose
execution context this async resource was created.
* resource <Object> Reference to the resource representing the async
operation, needs to be released during destroy .
Called when a class is constructed that has the possibility to emit an
asynchronous event. This does not mean the instance must call
before / after before destroy is called, only that the possibility
exists. This behavior can be observed by doing something like opening a resource then
closing it before the resource can be used. The following snippet demonstrates
this. import { createServer } from 'node:net' ;
createServer () . listen ( function () { this . close () ; } ) ;
// OR
clearTimeout ( setTimeout ( () => {}, 10 )) ;
require ( 'node:net' ) . createServer () . listen ( function () { this . close () ; } ) ;
// OR
clearTimeout ( setTimeout ( () => {}, 10 )) ;
javascript copy
Every new resource is assigned an ID that is unique within the scope of the
current Node.js instance.
type #
The type is a string identifying the type of resource that caused
init to be called. Generally, it will correspond to the name of the
resource's constructor. The type of resources created by Node.js itself can change in any Node.js
release. Valid values include TLSWRAP ,
TCPWRAP , TCPSERVERWRAP , GETADDRINFOREQWRAP , FSREQCALLBACK ,
Microtask , and Timeout . Inspect the source code of the Node.js version used
to get the full list. Furthermore users of AsyncResource create async resources independent
of Node.js itself. There is also the PROMISE resource type, which is used to track Promise
instances and asynchronous work scheduled by them. The Promise s are only
tracked when trackPromises option is set to true . Users are able to define their own type when using the public embedder API. It is possible to have type name collisions. Embedders are encouraged to use
unique prefixes, such as the npm package name, to prevent collisions when
listening to the hooks.
triggerAsyncId #
triggerAsyncId is the asyncId of the resource that caused (or "triggered")
the new resource to initialize and that caused init to call. This is different
from async_hooks.executionAsyncId() that only shows when a resource was
created, while triggerAsyncId shows why a resource was created. The following is a simple demonstration of triggerAsyncId : import { createHook , executionAsyncId } from 'node:async_hooks' ;
import { stdout } from 'node:process' ;
import net from 'node:net' ;
import fs from 'node:fs' ;
createHook ( {
init ( asyncId , type , triggerAsyncId ) {
const eid = executionAsyncId () ;
fs . writeSync (
stdout . fd ,
` ${ type } ( ${ asyncId } ): trigger: ${ triggerAsyncId } execution: ${ eid } \n ` ) ;
},
} ) . enable () ;
net . createServer ( ( conn ) => {} ) . listen ( 8080 ) ;
const { createHook , executionAsyncId } = require ( 'node:async_hooks' ) ;
const { stdout } = require ( 'node:process' ) ;
const net = require ( 'node:net' ) ;
const fs = require ( 'nod
Links found on this page
- Skip to content [direct]
- Node.js [direct]
- About this documentation [direct]
- Usage and example [direct]
- Assertion testing [direct]
- Asynchronous context tracking [direct]
- Buffer [direct]
- C++ addons [direct]
- C/C++ addons with Node-API [direct]
- C++ embedder API [direct]
- Child processes [direct]
- Cluster [direct]
- Command-line options [direct]
- Console [direct]
- Crypto [direct]
- Debugger [direct]
- Deprecated APIs [direct]
- Diagnostics Channel [direct]
- DNS [direct]
- Domain [direct]
- Environment Variables [direct]
- Errors [direct]
- Events [direct]
- File system [direct]
- FFI [direct]
- Globals [direct]
- HTTP [direct]
- HTTP/2 [direct]
- HTTPS [direct]
- Inspector [direct]
- Internationalization [direct]
- Iterable Streams API [direct]
- Modules: CommonJS modules [direct]
- Modules: ECMAScript modules [direct]
- Modules: node:module API [direct]
- Modules: Packages [direct]
- Modules: TypeScript [direct]
- Net [direct]
- OS [direct]
- Path [direct]
- Performance hooks [direct]
- Permissions [direct]
- Process [direct]
- Punycode [direct]
- Query strings [direct]
- Readline [direct]
- REPL [direct]
- Report [direct]
- Single executable applications [direct]
- SQLite [direct]
- Stream [direct]
- String decoder [direct]
- Test runner [direct]
- Timers [direct]
- TLS/SSL [direct]
- Trace events [direct]
- TTY [direct]
- UDP/datagram [direct]
- URL [direct]
- Utilities [direct]
- V8 [direct]
- Virtual File System [direct]
- VM [direct]
- WASI [direct]
- Web Crypto API [direct]
- Web Streams API [direct]
- Worker threads [direct]
- Zlib [direct]
- Code repository and issue tracker [direct]
- Index [direct]
- 26.x [direct]
- 25.x [direct]
- 24.x LTS [direct]
- 23.x [direct]
- 22.x LTS [direct]
- 21.x [direct]
- 20.x [direct]
- 19.x [direct]
- 18.x [direct]
- 17.x [direct]