Overview
In Node.js, event emitters serve as objects that indicate the conclusion of a specific action by dispatching a message. Developers utilizing JavaScript can create scripts that monitor events from an event emitter and subsequently execute functions whenever the event occurs. In this scenario, an event consists of a unique identifying string along with any relevant data that must be communicated to the listeners.
In Node.js, when we seek to execute one action after the completion of another, we typically employ asynchronous programming strategies, such as utilizing nested callbacks or promise chaining. Nevertheless, these approaches tend to tightly bind the initiating action to the subsequent action, complicating any future modifications to the resultant behavior. A more effective way to structure this interaction is by leveraging event emitters, which implement the publish-subscribe design pattern. In this pattern, the publisher—referred to as the event emitter—dispatches a message or event, while the subscriber takes in that message and acts upon it. This exemplifies the application of a software architecture pattern. A key advantage of this pattern is that it allows the publisher to operate independently of the subscribers. When a publisher broadcasts an event, it is the responsibility of the subscribers to react accordingly. Consequently, if we wish to alter the behavior of our application, we do not need to change the publisher; instead, we can simply adjust the way the subscribers handle the events.
In this article, we will explore the process of creating an event listener for the JavaScript TicketManager class, which facilitates the purchasing of tickets. Upon the purchase of a ticket, the buy event will be activated, and we will establish listeners for this event. Furthermore, this guide will illustrate how to manage event subscribers and address erroneous events originating from the source.
Contents Table
- Comprehending EventEmitter
- Essential Ideas for EventEmitter
- Using addListener to create a listening event
- Removing an instance of an event
- Advanced EventEmitter Features
- The Best Ways to Use EventEmitter
- In summary
Node.js is renowned for its event-driven, asynchronous architecture, which allows it to manage multiple operations simultaneously without hindering the progress of other tasks. At the core of this architecture lies the EventEmitter class, which is part of the events module. This fundamental component underpins many critical functionalities of Node.js, including file handling and server frameworks.
Comprehending EventEmitter
Managing events becomes straightforward and flexible through the use of EventEmitter. This can be likened to a publisher-subscriber model where:
- Emitters broadcast named events.
- Listeners connect callback functions to these events to subscribe to (respond to) them.
This system enhances modularity and scalability by facilitating independent communication among different components of the application.
Syntax:
// Creation of a constant reference of EventEmitter
const EventEmittter = require('events');
// Initialization of instance of EventEmitter
const emitter = new EventEmitter();
Essential Ideas for EventEmitter
Events are Triggered: When an event is triggered, all listeners that have been registered are informed.
Event Monitoring: It is possible to establish callback functions or listeners for specific events. When the corresponding event is triggered, these listeners receive notifications.
Eliminating Listeners: In situations where listeners are no longer necessary, you have the option to remove them. This practice contributes to efficient resource management.
Using addListener to create a listening event
In order to adhere to the event requirements, it is essential to first establish a listener that will handle the callbacks that are dispatched and subsequently execute the required actions. The EventEmitter's addListener method enables us to set up an event listener. The addListener method proves to be quite beneficial, as it prevents the need to duplicate event definitions by adding them to the end of an array. Moreover, it permits us to invoke addListener multiple times, facilitating the management of various event instances.
Triggering an event: In Node.js, every event is identified by a specific name, allowing us to utilize the emit function to initiate an event while also sending any parameters to the listener function associated with that event.
Syntax:
emitter.addListener(eventName, listener);
emitter.emit(eventName, arg1,arg2,...)
Example: This shows how to use the addListener method to add events and create an EventEmitter.
Code:
// First we need to Import the events module
const EventEmitter = require('events');
// Initialization of instance of EventEmitter to be used
const emitter = new EventEmitter();
// Adding a listener to the event
emitter.addListener('Hello', (name) => {
console.log("Hello " + name);
});
// Emitting the Hello
emitter.emit('Hello', "welcome to the page");
Output
Removing an instance of an event
To remove a specific listener from an event, we can utilize the removeListener method. On the other hand, if we want to remove all instances of listeners associated with an event, we can employ the removeAllListeners method.
Syntax:
// To remove any single listener from the event emitter.removeListener(eventName, listener)
// To remove all listeners of the event emitter.removeAllListeners(eventName)
Example: An example of how to remove an event's event listener.
Code:
// Importing the events module
const EventEmitter = require('events');
// Initialization of instance of EventEmitter to be used
const emitter = new EventEmitter();
// Creation of events
const main1 = (msg) => {
console.log("Message from main1: " + msg);
};
const main2 = (msg) => {
console.log("Message from main2: " + msg);
};
// Registering main1 and main2 with the printEvent
emitter.addListener('printEvent', main1);
emitter.addListener('printEvent', main2);
//Calling the created event
emitter.emit('printEvent', "Hello all");
// Removing all the listeners associated with the event
emitter.removeAllListeners('printEvent');
// Calling the event again but it doesn't prints output
// as all listeners are removed
emitter.emit('printEvent', "Welcome back");
Output
As illustrated in the output above, it is evident that despite the event being triggered on two occasions, the output was generated only a single time. This is due to the removal of the event listeners, resulting in the absence of any listeners at the time the event was emitted for the second time.
Advanced EventEmitter Features
The EventEmitter class offers sophisticated functionalities such as the ability to handle multiple listeners, manage error situations, and additional capabilities.
Including More Listeners
For a single event, it is possible to attach multiple listeners, and these listeners will be invoked sequentially based on the order in which they were registered.
Code:
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
eventEmitter.on('main', (main) => {
console.log('First Event:', main);
});
eventEmitter.on('main1', (main1) => {
console.log('Second Event:', main1);
});
eventEmitter.emit('main', 'EventEmitter');
eventEmitter.emit('main1', 'EventEmitter');
Output
Once Listeners
The once method registers an event listener that is automatically removed after it is invoked a single time, specifically the next occasion the event is triggered.
Code:
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
eventEmitter.once('Emit', () => {
console.log('Emitter');
});
eventEmitter.emit('Emit'); // Output: Emitter
eventEmitter.emit('Emit'); // No output
Output
Removing Listeners
The removeListener function enables the removal of specific listeners, whereas the removeAllListeners function removes all listeners associated with a particular event.
Code:
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
const Emitter = () => {
console.log('No Output');
};
eventEmitter.on('main', Emitter);
eventEmitter.removeListener('main', Emitter);
eventEmitter.emit('main'); // No output
Output
The best ways to use EventEmitter
Restricting listeners: In order to avoid memory leaks, it is essential to limit the quantity of listeners. To effectively control the upper limit of listeners, utilize the setMaxListeners method.
Properly manage errors: To guarantee that errors are detected and addressed smoothly, it is essential to consistently implement error listeners.
Remove unnecessary listeners: In order to optimize resource usage, it is essential to eliminate listeners that are no longer in use.
Utilize clear and descriptive names for events: To enhance both readability and maintainability, assign events names that are meaningful and descriptive.
In summary
In this tutorial, you learned how to utilize Node.js event emitters to initiate events. By employing the emit method of an EventEmitter instance, you triggered events, and subsequently, you applied the on and once methods to monitor these events and execute code whenever the event occurred. Moreover, you established a listener for an error event and leveraged the listenerCount method to oversee and manage the listeners effectively.
In order to achieve equivalent functionality using callbacks and promises, our ticket management system requires integration with both the database and email service components. The event was decoupled from the implementations due to our utilization of event emitters. Furthermore, any module that has access to the ticket manager can monitor its events and take corresponding actions. If you wish for internal or external Node.js modules to observe the actions of your object, it is advisable to create an event emitter. This approach will enhance scalability.