Node.js 8 version released a new module called async_hooks
. It provides an easy-to-use API to track the lifetime of async resources in Node.js applications.
The Node team introduced this module back in 2017. However, it is still in the experimental state.
The asynchronous resources mentioned here are the objects created by Node.JS that have associated callback and can be called multiple times. Some examples of asynchronous resources are Timeouts
, Promises
, TCPWRAP
, Immediates
, etc.
We’ll learn more about Async hooks and their use cases in this blog. Let’s get going then-
Why Do We Need Async Hooks?
Async process creates async resources, for example, file read, database read operation, external API call. So naturally async resources keep track of callbacks, once the process completes. But, if we need to track the async resource like what is happening in the middle of an async resource execution, we don’t have any way to do that.
The typical lifecycle of such an async resource is similar to this:

To solve this concern, Nodejs provided async hooks to spy on life cycle of async resources.
Enough talking, show me the code!
Hello word to async hooks-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<strong>const </strong>fs = require(<strong>'fs'</strong>); <strong>const </strong>{ fd } = process.stdout; <strong>const </strong>async_hooks = require(<strong>'async_hooks'</strong>) <strong>function </strong>init(asyncId, type, triggerAsyncId, resource) { fs.writeSync(fd, <strong>`Init callback async id --> </strong>${asyncId} <strong>\n`</strong>); } <strong>function </strong>destroy(asyncId) { fs.writeSync(fd, <strong>`Destroy callback async id --></strong>${asyncId} <strong>\n`</strong>); } <strong>const </strong>asyncHook = async_hooks.createHook({ init: init, destroy: destroy }); asyncHook.enable(); <em>setTimeout</em>(()=>{ <em>//do nothing </em>}, 1000); |
1 |
//output<br>/*<br>Init callback async id --> 4<br>Destroy callback async id -->4<br>*/ |
In the example above, we have setTimeout
is making an async operation. We have created two async hooks init
and destroy
. When we execute the code, we can see that it is calling init
first, and then callsdestroy
function. You might be wondering why we are using fs.writeSync
to print on console rather than using console.log
.
Console.log
is async function itself, so this will cause async hooks again, and will cause infinite recursion. So we can not use any async code inside async hooks. We will discuss it later on again in this article.
Async Hooks APIs
Essentially, the async hooks API provides these five key event functions that we call during different time and instances of the resource’s lifecycle, to track the async resources.

You have to specify the event that you want to trigger out of the following while creating an instance.
All the callbacks are optional. Let’s make this statement a little more obvious- It means if the cleanup data of the resource is to be tracked, then you only need to pass the destroy
callback.
init
The init
callback is called whenever a call is created that has the possibility of triggering an asynchronous event. Just for the record, at this point, we’ve already associated the hook with an async resource.
init
callback receives these parameters when called-
asyncId
: Each async resource, when identified, gets a unique ID.type
: It depicts the type of the async resource in string form that triggered init callback.triggerAsyncId
:asyncId
of the resource for whose context the async resource was created. It shows the reason behind creating a specific resource.resource
: It represents the reference to the async operation releasing duringdestroy
.
All the other callbacks get only one parameter- asyncId
.
Before
Whenever an async operation initiates or completes, a callback notifies the user of its status. The before
callback is called right before this mentioned callback is executed, and the relevant resource will be assigned with a unique asyncId
identifier.
The before
callback can be called any times from 0 to n. For instance, when the asynchronous operation gets cancelled, it will be called 0 times, on the other hand, the persistent type resources can call it multiple times.
After
Similar to before
, it is called post-execution of the relevant asynchronous resource or right after when the specified callback in before
callback finishes its execution.
Destroy
It’s quite easy to guess, isn’t it? Yes, you guessed it right!
It is called every time the asynchronous resource, corresponding to the unique asyncId
, is destroyed regardless of whatever happened to its callback function.
However, in some cases, the resource depend upon the garbage collection for its cleanup which might cause a memory leak in the application, which results in avoid calling destroy
. If the resource does not rely upon the garbage, then it won’t be a problem and destroy will do the cleaning.
promiseResolve
This callback is triggered when the Promise
gets its resolve function, which is invoked either directly or by some external means to resolve a promise.

Use Cases of Async Hooks
Listed below are some major features and use cases of async hooks-
– Promise Execution Tracking
Async hooks play a vital role tracking the lifecycle of promises and their execution, as promises are also asynchronous resources.
Whenever a new promise is created, the init
callback runs. The before
and after
hooks run pre- and post-completion of a PromiseReactionJob
and the resolve
hook is called when a promise is resolved.
– Web Request Context Handling
Another major use case of Async Hooks is to store relevant information in context to the request during its lifetime. This feature becomes highly useful to track the user’s behavior in a server.
With async hooks, you can easily store the context data and access it anywhere and anytime in the code.
The process starts with a new request to the server, which initiates calling createRequestContext
function to get data to store in a Map. Every async operation initiated as part of this request will be saved in the Map along with the context data (Here init
plays an important part).
Next, destroy
keeps the size of the Map under control and do the cleaning. This is how you can get the current execution context by calling getContextData
anytime.
– Error Handling with Async Hooks
Whenever an async hook callback throws an error, the application follows the stack trace and exits due to an uncaught exception. Unless you run the application with-abort-on-uncaught-exception
, which will print the stack trace exiting the application, the exit callbacks will still be called.
The error handling behavior is due to the fact that all these callbacks run at potentially unstable points, for instance during construction or destruction of a class. This process prevents any unintentional and potential abort to the process by closing it quickly.
– Printing in Async Hooks
Printing is an asynchronous operation and console.log()
triggers calling async callbacks. However, using such asynchronous operations inside async callbacks causes infinite recursion.
For instance, when init
runs, the console.log()
will trigger another init
callback causing endless recursion and increasing stack size.
To avoid this, you should use a synchronous operation like fs.writeFileSync(file, msg, flag)
while debugging as it will print to the file without invoking AsyncHooks
recursively.
If the logging requires an asynchronous operation, you can track what caused the async operation to initiate using AsyncHooks. As it was logging itself that invoked the AsyncHooks callback, you can skip it which will break the infinite recursion cycle.
– Enhanced Stack Traces
The creator of Node.js, Ryan Dahl, talked about debugging problems in node.js due to event loops, which kills the stack trace. As the async hooks facilitate better tracing of async resources, it allows developers to improve and enrich the stack trace.
Bottom Line
Do you know that you can also measure the duration of an asynchronous operation in real-time? Yes, you can, but by integrating Async hooks module with Performance API module.
Well, this was all about async hooks. I would suggest you to refer to this link if you want to learn more about async hooks.
Thanks for reading!!
Don’t forget to share your response with us in the comment section!
Thank you for sharing this amazing article! Becuse I am working on node.js for my project I am regularly read about node.js on the internet and I read your article and that was well written and I learn something New about node.js in your post. Also If you have any tips for node.js then keep sharing with me.