Sling Academy
Home/Node.js/How to use Async Hooks in Node.js

How to use Async Hooks in Node.js

Last updated: December 28, 2023

Overview

Asynchronous operations are a cornerstone of Node.js, enabling non-blocking I/O operations. However, tracking the lifecycle of asynchronous operations can be challenging. This is where Async Hooks come into play. Async Hooks is an API provided by Node.js which allows developers to monitor and manage the state of asynchronous operations. In this tutorial, we’ll go through the basics of Async Hooks, explore some practical examples, and understand best practices when using this powerful feature.

A Quick Introduction to Async Hooks

Async Hooks provide the necessary hooks to track the lifecycle events of asynchronous resources in Node.js, such as promises, timers, or HTTP requests. The API offers several hooks: init(), before(), after(), and destroy(), which are called during various phases of an asynchronous operation.

Note: Working with Async Hooks can have performance implications and should be used judiciously.

Basic Example

const async_hooks = require('async_hooks');
const fs = require('fs');

// Target asynchronous operation for tracking
function asyncOperation() {
  setTimeout(() => {
    fs.writeFileSync('/tmp/dummyfile', 'Data');
  }, 100);
}

// Initialize async hook
const hook = async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    fs.writeSync(1, `Async operation started (ID: ${asyncId})\n`);
  }
}).enable();

asyncOperation();

Advanced Usage

Now that we understand the basics, let’s dig into a more complex scenario. Suppose we want to track a specific type of resource. We can use the type parameter in the init hook to accomplish this.

// ... same setup as above

const hook = async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    if (type === 'Timeout') {
      fs.writeSync(1, `Timer started (ID: ${asyncId})\n`);
    }
  }
}).enable();

// ... same usage as above

Building on this, we can maintain a context for each asynchronous operation and access it later in the lifecycle. For instance, let’s keep track of the time when each asynchronous operation starts.

// ... same setup as above

const asyncResourceMap = new Map();

const hook = async_hooks.createHook({
  init(asyncId) {
    asyncResourceMap.set(asyncId, { startTime: process.hrtime() });
  },
  before(asyncId) {
    const resource = asyncResourceMap.get(asyncId);
    resource.beforeTime = process.hrtime();
  },
  after(asyncId) {
    const resource = asyncResourceMap.get(asyncId);
    resource.afterTime = process.hrtime();
    const duration = resource.afterTime - resource.beforeTime;
    fs.writeSync(1, `Async operation (ID: ${asyncId}) took ${duration} nanoseconds\n`);
  },
  destroy(asyncId) {
    asyncResourceMap.delete(asyncId);
  }
}).enable();

// ... same usage as above

Conclusion

In this tutorial, we uncovered the abilities of Async Hooks to provide deep insights into asynchronous operations in Node.js applications. From tracking async resources to timing their executions, Async Hooks can be a valuable tool for debugging and performance monitoring. It’s important to remember that while they are powerful, they should be used sparingly due to their potential performance impact. With careful implementation, Async Hooks can help you gain control over asynchronicity and maintain the robustness of your Node.js applications.

Next Article: How to Setup a Node.js Cluster for Speed & Stability

Previous Article: Setting Up Docker Compose with Node.js, Express, Sequelize, and MySQL

Series: Node.js Intermediate Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates