DEV Community

loading...
Cover image for Node.js Event Emitter

Node.js Event Emitter

Taslan Graham
Taslan Graham is a web developer with interest in the JavaScript language and JS based technologies and frameworks.
Originally published at taslangraham.com Updated on ・5 min read

Node's event-driven architecture allows us to execute certain actions when something happens. This is done via objects (called "emitters") which can emit named events that cause functions ("listeners") to be executed. Objects that emit events are instances of node's EventEmitter class, made available via the events module. In this article we'll look at node's event emitter.

Creating an Emitter

Let's create an event to explore some of basic concepts with node's EventEmitter

// Require in the events module 
const EventEmitter = require('events');
const carEvent = new EventEmitter();
Enter fullscreen mode Exit fullscreen mode

The events module provides us with the EventEmitter class. We then create an instance of EventEmitter called carEvent. Now let's explore some of the methods available to us.

Adding a listener

As mentioned earlier listeners are callbacks that gets executed when we emit a named event. Here's how you'd create an event listener on our carEvent emmiter.

carEvent.on('start', function(){
  console.log('Started the car.');
});
Enter fullscreen mode Exit fullscreen mode

Here we are registering a listener for the event named start. This will be executed when we emit an event of said name.

We can also add multiple listeners to a single event. Let's add another:

carEvent.on('start', function(){
  console.log('Car started. Ready to go!');
});
Enter fullscreen mode Exit fullscreen mode

Next we'll emit events to trigger these listeners.

Emitting an Event

All listeners for an event will be called synchronously in the order in which they were registered.

We trigger the listener(s) for an event by calling the emit() method with the name of the event as the first argument. Any subsequent arguments will be passed on as arguments to the listeners.

carEvent.emit('start', 'Hello! ');
// Started the car.
// Car started. Ready to go!
Enter fullscreen mode Exit fullscreen mode

Above we emitted the start event which resulted in all listeners attached to the start event being executed. Now lets update our second listener to make it accept an argument.

carEvent.on('start', function(greeting){
  console.log(greeting, 'Car started. Ready to go!');
});
Enter fullscreen mode Exit fullscreen mode

Now we emit the start event and get the following:

carEvent.emit('start', 'Hello!');
// Started the car.
// Hello! Car started. Ready to go!
Enter fullscreen mode Exit fullscreen mode

Removing a listener from an event

The removeListener() method removes a listener from an event. This takes the name of the event, and the handler function to be removed as arguments. Calls to this method only removes a single instance of a listener, so if you have a listener that was added multiple times then you'd have to call the removeListener() method multiple times to remove each listener.

function a(){
  console.log('Called listener function');
}

// Add listener to event
carEvent.on('A', a);

// Emit event
carEvent.emit('A');
// Called listener function

// Remove listener
carEvent.removeListener('A', a);

// Emit event again
// Nothing happens, event was removed
carEvent.emit('A');
Enter fullscreen mode Exit fullscreen mode

The removeListener method emits an event, removeListener, after the listener has being removed.

More methods

The on() and emit() methods are the most commons ones used when when working with event emitters in node. However, lets take a look at some other useful methods available to us.

Once

The once() method adds a listener that will be executed only, you guessed it :) , once.

// Adds a listener to be executed once
carEvent.once('stop', function(message){
  console.log(message);
});
Enter fullscreen mode Exit fullscreen mode

Now when emit the stop event, node will remove the listener(from list of listeners attached to the event) then invoke it.

// Executes the first time we emit the stop event
carEvent.emit('stop', 'Stopping....');
// Stopping....

// Emit the stop event a second time
// Nothing happens
carEvent.emit('stop', 'Stopping....');
Enter fullscreen mode Exit fullscreen mode

setMaxListeners

The setMaxListeners() method allows you to set to the maximum number of listeners that can be attached to a single event. The value can be set to Infinity (or 0) to indicate an unlimited number of listeners.

// Sets a maximum of two listeners for any event on the carEvent emitter
carEvent.setMaxListeners(2);
Enter fullscreen mode Exit fullscreen mode

If we add more than two listeners to any event then we'll get a warning like the following:

// Add thre listeners to a single event
carEvent.on('eventA', function(greeting){});
carEvent.on('eventA', function(greeting){});
carEvent.on('eventA', function(greeting){});
Enter fullscreen mode Exit fullscreen mode
(node:17787) Warning: Possible EventEmitter memory leak detected. 3 eventA listeners added. Use emitter.setMaxListeners() to increase limit

listeners

The listeners() method returns an array of the listeners registered for an event.

const listeners = carEvent.listeners('start');
console.log(listeners);
// [ [Function], [Function] ]
Enter fullscreen mode Exit fullscreen mode

eventNames

Returns an array listing the name of events for which the emitter has registered listeners.

console.log(carEvent.eventNames());
// [ 'start', 'stop', 'eventA' ]
Enter fullscreen mode Exit fullscreen mode

Extending The EventEmitter Class

We can create our own objects that has its own set of properties and methods along with the ones provided by node's EventEmitter.

const EventEmitter = require('events');

class Car extends EventEmitter{
  constructor(brand, year){
    super();
    this.brand = brand;
    this.year = year;
  }

  turnRadioOn(){
    console.log('radio turned on');
  }
}
Enter fullscreen mode Exit fullscreen mode

Above we created a class that inherits from the EventEmitter class as well as having two properties(brand, and year) of its own along with a method, turnRadioOn.

Now instances of the Car class will have access to both the properties and methods on the Car class as well as all the ones inherited from the EventEmitter class.

const car = new Car('BMW', '2021');

// Adds a listener
car.on('start', function(){ console.log(this.brand + ' started') });

// Emit the event
car.emit('start');
// BMW started

// Call method defined on Car class
car.turnRadioOn();
// radio turned on
Enter fullscreen mode Exit fullscreen mode

Conclusion

Node's EventEmitter allows us to create objects with listeners that gets executed when we emit an event that the listener is registered to.
We covered methods including the on(), emit(), removeListener() methods. We also looked at how we can extend the EventEmitterwhen creating our own classes.

Did you find this useful? Let me know if the comments. Until next time, think, learn, create, repeat!

Discussion (11)

Collapse
sudonitin profile image
Nitin Sahu

What are some practical use of event emitters?

Collapse
anaekin profile image
Animesh Jain

Let's say, when your application starts, you are checking the connection to the database and/or doing some other operations which are in different files and you want to inform your app.js file about the connection or pass the information regarding certain operation in multiple files.
You can send an event across the app and wherever you are listening for that event, you can then perform some other operation like retry if db connection fails.
This is useful for communicating between multiple files, passing data between two js files etc.

Collapse
zulfadhli4141 profile image
Zulfadhli Zakari

Do you have any example Express project using event emitter?

Thread Thread
codancepfc profile image
@codance

this is effectively what socket.io does.

Collapse
rish15 profile image
rish srivastav
this snippet is from pdfmake which creates a buffer and stringBase64

const pdfDoc = printer.createPdfKitDocument(docDefinition);
let chunks = [];
  pdfDoc.on("data", (chunk) => {
    chunks.push(chunk);
  });
  pdfDoc.on("end", () => {
    const result = Buffer.concat(chunks).toString("base64");
    console.log({result})
  });
Enter fullscreen mode Exit fullscreen mode
Collapse
ctfrancia profile image
Christian Francia

To drive fellow developers crazy when trying to debug

Collapse
sahajranipa1 profile image
sahaj ranipa

Based on some action you can fire the particular event emitter just say on click certain button you want to fire some event or some code then you can use eventemitter I guess.

Collapse
stainlessray profile image
stainlessray

Home automation would be one. To extend the example from the article - car on, open garage door and turn on the lights.

Collapse
ivandotv profile image
Ivan V. • Edited

Nice article.
For people asking for real world application of the
Event Emitter class, well it enables you to build abstractions like the event bus pattern which enables you to decouple parts of your system (components) or anything else that shouldn't be tightly coupled together.
I've made one such library and wrote an article about it here on dev.
Event Bus Pattern via Native EventEmmiter Class

Collapse
yw662 profile image
yw662 • Edited

this is exactly the EventTarget we have in DOM, all except on instead of addEventListener, and we can use Element instead.

And, btw, EventTarget is in node.js since 15.

Collapse
kak_kotyavo profile image
KAK KOTYAVO!

I want to say that it is better to use EventEmitter2 as the main solution, since it is really faster.