Why and how to use the the Node.js Event Emitter in real projects?

The Observer pattern and the Event Emitter

The Observer pattern defines an object (called the subject) that can notify a set of observers (or listeners) when a change in its state occurs.

It can be implemented in OOP by using a class that can register and store listeners in an array and calls them when something happens.

In Node.js it can be implemented using the EventEmitter class which is imported from the events built-in module. It allows to emit and listen for events (with multiple listeners).

EventEmitter Illustration

The EventEmitter is exported from the events core module:

const { EventEmitter } = require("events");
const emitter = new EventEmitter();

The essential methods of the EventEmitter are as follows:

  • on(event, listener): This method allows us to register a new listener (a function) for the given event type (a string).

  • once(event, listener): This method registers a new listener, which is then removed after the event is emitted for the first time.

  • emit(event, [arg1], [...]): This method produces a new event and provides additional arguments to be passed to the listeners.

  • removeListener(event, listener): This method removes a listener for the specified event type.

When to use the EventEmitter

It can be used in backend projects and here's a real example where I used it, In an LMS, when a teacher publishes a new lesson I need to send emails and notifications to all the students that are subscribed to the teacher, so we shouldn't put that code in the publish lesson request so the teacher doesn't wait for the emails and notifications to be sent to get a success response and we separate the publish lesson logic from the emails and notifications part to have clean code by achieving the separation of concerns principle. Another example is when you need to update a real-time dashboard or to send a notification to your investors when new users signup.

How to use the EventEmitter in real projects

Create this folder structure:

/events
    /subscribers
        /lessons.subscriber.js
        /users.subscriber.js
    /emitter.js
    /index.js

In /emitter.js: Create a new EventEmitter and export it.

const { EventEmitter } = require("events");

module.exports = new EventEmitter();

In /index.js Import the created EventEmitter and export it with the events' names.

const EventEmitter = require("./emitter");

module.exports = {
  EventEmitter,
  events: {
    LESSON_PUBLISHED: "LESSON_PUBLISHED",
    NEW_SIGNUP: "NEW_SIGNUP"
  }
};

we can also separate the events' names in a different file but there's no need to.

In subscribers/users.subscriber.js: Import the events and the EventEmitter instance and listen to the events.

const { events, EventEmitter } = require("../");

EventEmitter.on(events.NEW_SIGNUP, user => {
  // Your logic
}

Now we are done with the listeners part, in your controller or service you can import the EventEmitter instance and the events' names then emit the event and pass the data you want like:

EventEmitter.emit(events.NEW_SIGNUP, user);

I hope you liked this article, you can follow the blog if you want more.

LinkedIn