The EventEmitter class is the node implementation of the Pub/Sub pattern. It is a part of the events module and powerful utility that could be handy in many cases. We are already using an implementation of the EventEmitter every time we use the .on() function to listen for an event. The EventEmitter class will provide us with methods that will allow us to listen to and emit custom events.

Importing The EventEmitter

As mention, it is a class (a function constructor) that is part of the events module. Therefore, we would have to import the events modules first and then instantiating the EventEmitter.

const events = require('events');

const ee = new events.EventEmitter();

We require() the events module and then instantiate a new constant ee of the EventEmitter with the new keyword. Now, we can pull the EventEmitter directly from the events module without having to define an extra events constant.

const ee = require('events').EventEmitter;

Emitting Custom Events

Let's start by triggering or emitting a custom event. To emit an event we use the emit() function on the EventEmitter.

ee.emit('CustomEvent', ...args);

The first argument of the emit() method is the name of the custom event, and the second argument is a list of arguments that will be passed to the callback function of the on() function when listening to the event which we will see in the next section.

The emit() will, synchronously, call each of the listeners that are registered for the event named CustomEvent, in the order they were registered, passing the supplied arguments to each. It will return true if the event had listeners, and false otherwise.

Listening to Custom Events

Now that the custom event can be triggered or emitted, we can listen to it using the on() method.

ee.on('CustomEvent', (...args) => {
    //...
});

It should look familiar because it had the same syntax of the any on() method that we dealt with before when listening to events. The first argument is the custom event name and the second argument is the callback function.

There is another method for listening to events; it is the once() which has the same syntax of the on() method. However, it will add a one time listener function to the event.

// one time listener
ee.once('CustomEvent', (...args) => {
    //...
});

Both on() and once() methods will return a reference to the EventEmitter so that calls can be chained.

By default, event listeners are invoked in the order they are added. The prependListener() method can be used as an alternative to add the event listener to the beginning of the listeners array.

Use Cases and Examples

Let's start with a simple example that shows how to utilize the EventEmitter.

const EventEmitter = require('events').EventEmitter;

const ee = new EventEmitter();

ee.on('MyCustomEvent', name => {
    console.log(`Hello, ${name}.`);
});

ee.emit('MyCustomEvent', 'Jack'); // Hello, Jack.

Pretty much self-explanatory. We require the EventEmitter, and instantiate a new constant ee of the EventEmitter. Then we start listening to an event MyCustomEvent which when triggered will result in executing the callback that is logging a "hello" message with a name that will be passed to it. Later on we emit the custom event MyCustomEvent passing 'Jack' as a second parameter (which is the callback parameter).

We would rarely encounter the EventEmitter as a standalone implementation; we would mostly see it inherited in other customed object or module. Let's see an example of a User constructor function that will inherit the EventEmitter to extend its functionality.

const EventEmitter = require('events').EventEmitter;
const util = require('util');

let Product = function (name, price) {
    this.name = name;
    this.price = price;
};

util.inherits(Product, EventEmitter);

let product1 = new Product('Product One', 599.99);

product1.on('DiscountEvent', function (percentage) {
    let priceWithDiscount = (this.price - ((this.price * percentage) / 100)).toFixed(2);
    console.log(`'${this.name}' is on sale. Get it now with ${percentage} at $${priceWithDiscount} (originally $${this.price})`);
});

product1.emit('DiscountEvent', 20);
// 'Product One' is on sale. Get it now with 20 at $479.99 (originally $599.99)

We required the util module so we can take advantage of the inherits() method which will basically inherit the prototype from the EventEmitter into the Product. The Product function constructor will have name and price. product1 is an instance of the Product, which is listening to a DiscountEvent.

In real life, the EventEmitter has some applications in IoT. For instance, when a light is turned on or off, or when a door is opened or closed, we would have some sort of listener that will do some useful functionality when the event is triggered or emitted.