Skip to main content

Understanding Event Emitters in NodeJS



nodejs-event-emitters

The core idiom of NodeJS is Event Emitters. Most of the NodeJS Core Modules are built on top of the events module. In this tutorial, I will teach you what is Event Emitters and how we can make use of it in real-world scenarios.

What is Event Emitters?

You know that NodeJS is for javascript developers, but the other side of NodeJS is completely built in C++. The C++ side of NodeJS contains the libuv library which handles the events with the OS. Whenever an event completes in OS, libuv emits corresponding functions to happen. This concept is not available on the JavaScript side but NodeJS makes a fake Event Emitter concept which in turn become a popular module for most of the other NodeJS Core Modules like HTTP, FS, Streams etc.

Creating our own Event Emitters Concept:

To clearly understand what’s happening behind the scenes in NodeJS when using EventEmitters, we will build a simple EventEmitter class similar to NodeJS EventEmitters.
module.exports = class Emitter {
    constructor() {
        this.events = {};
    }

    on(type,listener) {
        this.events[type] = this.events[type] || [];
        this.events[type].push(listener);
    }

    emit(type) {
        if(this.events[type]) {
            this.events[type].forEach((listener) => {
                listener();
            });
        }
    }
}
I created a class named Emitter, Its constructor function creates an empty “events” object every time the Emitter class gets instantiated. The “on” method in the Emitter class is used to register the event with a listener function, the first line of the on method creates an empty event property if there’s no event with the same name in the “events” object. Otherwise, it assigns the older event property to it. Then, we push the listener function to the event property. The “emit” method in the Emitter class is used to emit the listener functions one by one corresponding to the event name passed inside the function as a parameter.

Using our Event Emitters:

var Emitter = require('./emitter');

var mobileEvents = new Emitter();

mobileEvents.on('call', () => {
    console.log('Ringing');
});

mobileEvents.on('call', () => {
    console.log("Vibrating");
});

console.log("make a call");
mobileEvents.emit('call');
To use our fake EventEmitters, we first require the module and then instantiate the Emitter class. As you know, The “on” method is used to register an event called “call” two times with two different listener functions. At the last line, The emit method is used to invoke all the listener functions. The output of the above code will be like this:
make a call
Ringing
Vibrating

Let’s make use of NodeJS Core EventEmitter:

To understand the concept of EventEmitters vividly, Let’s start thinking of a real-world example, your mobile is listening to a call event. When someone makes a call to your number, your mobile which is listening to the event will start (emit) to ring based on the settings you set up on your mobile.
const EventEmitter = require('events');

class mobileEvents extends EventEmitter {
    constructor(ringtone,vibration) {
        super();
        this.ringtone = ringtone;
        this.vibration = vibration;
    }

    ringing() {
        console.log(`${this.ringtone} Ringing`)
    }
}

const mobileEventEmitter = new mobileEvents('Titanic', true);

mobileEventEmitter.on('call', () => {
  mobileEventEmitter.ringing();
});

function callToMyFriend() {
    console.log('Connecting to your friend mobile');
    mobileEventEmitter.emit('call');
}

callToMyFriend();
  • Required the NodeJS events module.
  • Created a class named mobileEvents extended from core EventEmitter.
  • Inside the “mobileEvents” class, a constructor function is used in order to set up the ringtone and the vibration whenever an instance of this class gets instantiated.
  • At last, a method named “ringing” is added in order to show the user that the mobile is ringing.

The Event Emitter Methods:

There are several useful methods available in NodeJS Core “events” module. I will explain the most often used ones here.

The “on” and “addListener” Method in Event Emitter:

The “on” and “addListener” methods in EventEmitter are event registration methods. It registers an event with a listener function. It takes two parameters, a name of the event and the listener function.
mobileEventEmitter.on('call', () => {
  mobileEventEmitter.ringing();
});

mobileEventEmitter.on('call', () => {
  console.log("second event listener");
});


mobileEventEmitter.on('call', () => {
  console.log("third event listener");
});
An event can have more than one listener function. It’s better to limit the number of listener functions to below 10 per event (NodeJS restrict it too, to prevent the memory leaks).

The “emit” Method in Event Emitters:

While the “on” and “addListener” method is used to register an event, the “emit” method is used to emit the event, in other words, it invokes (calls) all the listener functions of the event.
mobileEventEmitter.emit("call");
When the compiler hits this line, it invokes all the listener functions of the event one by one in the order in which they are registered.

The “once” Method in Event Emitters:

The “once” method in EventEmitter is used to register a listener function, but in this case, once the event is emitted using the “emit” method, the listener functions which are registered using the once method will be removed from the events listener list.
mobileEventEmitter.once('call', () => {
    console.log("once listener is emitted");
});

mobileEventEmitter.emit('call');
mobileEventEmitter.emit('call');
When you try to emit the “call” event for two times, you will get an output as follows:
//first time event emitted,
Titanic Ringing
second listener
third listener
once listener is emitted

//second time event emitted,
Titanic Ringing
second listener
third listener

The “removeListener” Method in Event Emitters:

There may be times when you have to remove a particular listener function in an event. The “removeListener” method accepts two parameters, the name of the event and the listener function which you want to remove.
const listenerFunction = () => {
  console.log("I am listener funciton");
}

mobileEventEmitter.on('call', listenerFunction);

mobileEventEmitter.emit('call');
//output: I am listener function

mobileEventEmitter.removeListener('call', listenerFunction);

mobileEventEmitter.emit('call');
//output: false (when you print it in console)

The “removeAllListeners” Method in Event Emitters:

The “removeAllListeners” method wipe out all the listener functions from the event. It accepts an array of event names as a parameter. If you pass a single event name then the listener function corresponding to that event will be removed.
//removing single event listeners
mobileEventEmitter.removeAllListeners('call');

//removing multiples events listeners
mobileEventEmitter.removeAllListeners(['call','sms','data']);

Conclusion

There are so many other useful methods in NodeJS Event Emitters, I didn’t cover in this post, available in the NodeJS Events module. If you’re curious about it, take a look at NodeJS documentation on events module . If you have any other ideas or suggestions about NodeJS event emitters, please make a comment below. Thank You!

Comments

Popular posts from this blog

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functio...

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.compon...

How to solve Puppeteer TimeoutError: Navigation timeout of 30000 ms exceeded

During the automation of multiple tasks on my job and personal projects, i decided to move on  Puppeteer  instead of the old school PhantomJS. One of the most usual problems with pages that contain a lot of content, because of the ads, images etc. is the load time, an exception is thrown (specifically the TimeoutError) after a page takes more than 30000ms (30 seconds) to load totally. To solve this problem, you will have 2 options, either to increase this timeout in the configuration or remove it at all. Personally, i prefer to remove the limit as i know that the pages that i work with will end up loading someday. In this article, i'll explain you briefly 2 ways to bypass this limitation. A. Globally on the tab The option that i prefer, as i browse multiple pages in the same tab, is to remove the timeout limit on the tab that i use to browse. For example, to remove the limit you should add: await page . setDefaultNavigationTimeout ( 0 ) ;  COPY SNIPPET The setDefaultNav...