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();
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.');
});
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!');
});
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!
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!');
});
Now we emit the start event and get the following:
carEvent.emit('start', 'Hello!');
// Started the car.
// Hello! Car started. Ready to go!
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');
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);
});
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....');
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);
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){});
(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] ]
eventNames
Returns an array listing the name of events for which the emitter has registered listeners.
console.log(carEvent.eventNames());
// [ 'start', 'stop', 'eventA' ]
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');
}
}
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
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 EventEmitter
when creating our own classes.
Did you find this useful? Let me know if the comments. Until next time, think, learn, create, repeat!
Top comments (11)
What are some practical use of event emitters?
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.
Do you have any example Express project using event emitter?
this is effectively what socket.io does.
this snippet is from pdfmake which creates a buffer and stringBase64
To drive fellow developers crazy when trying to debug
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.
Home automation would be one. To extend the example from the article - car on, open garage door and turn on the lights.
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
this is exactly the
EventTarget
we have in DOM, all excepton
instead ofaddEventListener
, and we can useElement
instead.And, btw,
EventTarget
is in node.js since 15.I want to say that it is better to use EventEmitter2 as the main solution, since it is really faster.