Handle Asynchronous Events in Node.js

10 min read·Jan 1, 2026

In Node.js, the core API is built around an asynchronous event-driven architecture in which certain objects called "emitters" send named signals called "events" to other objects called "listeners" that perform specific actions in response.

The EventEmitter class

All objects that emit events are instances of the EventEmitter class defined in the node:events module:

const EventEmitter = require('node:events');

When the EventEmitter object emits an event, all the functions attached to that specific event are called synchronously.

Create an event emitter

To create an event emitter object, you can use the new keyword to instantiate the EventEmitter class:

const EventEmitter = require('node:events');

const emitter = new EventEmitter();

Emit named events

To emit a named event, you can use the emit() method of the event emitter instance:

emitter.emit(name, ...arguments?);

Where:

  • name is the name of the event.
  • ...arguments is a list of optional arguments used to send data alongside the named event.

Example

Let's consider this script:

const EventEmitter = require('node:events');

const emitter = new EventEmitter();

emitter.emit('data', 'Hello, World!');

When executed, the emitter instance will emit a "data" event containing the "Hello, World!".

Handle named events

To intercept and handle a named event, you can use the on() method of the event emitter instance:

emitter.on(event, listener);

Where:

  • event is the name of the emitted event.
  • listener is a callback function executed whenever the specified event is emitted, that takes are arguments the arguments specified in the .emit() method.

Note: Since different event emitter instances can emit the same event, only the listener attached to the instance that emitted the event will be triggered.

Example

Let's consider this script:

const EventEmitter = require('node:events');

const emitter = new EventEmitter();

emitter.on('data', (data) => {
  console.log(data);
});

emitter.emit('data', 'Hello, World!');

When executed, the emitter instance will intercept the "data" event and log the string passed alongside the event.

Which will produce this output:

Hello, World!

Handle events only once

By default, the listeners registered using the on() method are invoked every time the named event is emitted.

To invoke a listener only once, you can use the once() method instead:

emitter.once(event, listener);

Example

Let's consider this script:

const EventEmitter = require('node:events');

const emitter = new EventEmitter();

emitter.once('start', () => {
  console.log('Setting up...');
});

emitter.on('data', (data) => {
  console.log('Processing data...', data);
});

emitter.once('end', () => {
  console.log('Cleaning up...');
});

emitter.emit('start');
emitter.emit('start');
emitter.emit('data', 'Hello');
emitter.emit('data', 'World');
emitter.emit('end');
emitter.emit('end');

When executed, the emitter instance will emit each of the "start", "data", and "end" events twice, while using the once() method to intercept the "start" and "end" events only once, and the on() method to intercept all "data" events.

Which will produce this output:

Setting up...
Processing data... Hello
Processing data... World
Cleaning up...

Handle errors

When an error occurs within an EventEmitter instance, the typical action is for an error event to be emitted.

As a best practice, there should always be at least one listener attached to the error event in order to prevent the Node.js process from crashing.

Otherwise, whenever an error event is emitted, the error is thrown, a stack trace is printed, and the Node.js process exits.

Example

Let's consider this script:

const EventEmitter = require('node:events');

const emitter = new EventEmitter();

emitter.on('error', (error) => {
  console.error(error.message);
});

emitter.emit('error', new Error('Whoops!'));

When executed, the emitter instance will intercept and log the Error object of the "error" event, preventing the application from crashing.

Which will produce this output:

Whoops!

Summary

Here's a summary of what you've learned in this lesson:

  • The EventEmitter class is used to instantiate new event emitter objects.
  • The emit() method is used to emit events with optional data.
  • The on() method is used to intercept a specified event as many times as it is emitted.
  • The once() method is used to intercept a specified event only once.
  • The "error" event is used to intercept errors and prevent the application from crashing.

Enjoying the courses?

I've made these courses completely free so anyone can learn from them. If they've helped you and you'd like to actively support the work behind BackendBrewery, you can leave a tip:

Support BackendBrewery
Handle Asynchronous Events in Node.js | Backend Brewery