I read a lot of things about EventEmitter
. But I do not know in which case I need to use it in my Node.js application.
-
Possile duplicate of http://stackoverflow.com/questions/13438924/what-is-an-event-emitter – Kishore Aug 10 '16 at 20:46
3 Answers
Whenever it makes sense for code to SUBSCRIBE to something rather than get a callback from something. The typical use case would be that there's multiple blocks of code in your application that may need to do something when an event happens.
For example, let's say you are creating a ticketing system. The common way to handle things might be like this:
function addTicket(ticket, callback) {
insertTicketIntoDatabase(ticket, function(err) {
if (err)
return handleError(err);
callback();
});
}
But now, someone has decided that when a ticket is inserted into the database, you should email the user to let them know. That's fine, you can add it to the callback:
function addTicket(ticket, callback) {
insertTicketIntoDatabase(ticket, function(err) {
if (err)
return handleError(err);
emailUser(ticket, callback);
});
}
But now, someone wants to also notify another system that the ticket has been inserted. Over time, there could be any number of things that should happen when a ticket is inserted. So let's change it around a bit:
function addTicket(ticket, callback) {
insertTicketIntoDatabase(ticket, function(err) {
if (err)
return handleError(err);
TicketEvent.emit('inserted', ticket);
callback();
});
}
We no longer need to wait on all these functions to complete before we notify the user interface. And elsewhere in your code, you can add these functions easily:
TicketEvent.on('inserted', function(ticket) {
emailUser(ticket);
});
TicketEvent.on('inserted', function(ticket) {
notifySlack(ticket);
});

- 840
- 7
- 5
-
This answer is just perfect and applies the idea of "it allows you to have several listeners throughout your application" as suggested in this answer https://stackoverflow.com/questions/47010470/when-to-use-eventemitter-in-node-js – Skadoosh Feb 13 '21 at 18:43
-
2Why listen to the same event when you just can put them all in one listener? – alramdein Oct 27 '21 at 23:19
-
@alramdein for decoupling. When (or if) you will want to do another actions (in addition to slack and email - lets say send sms to the ticket buyer) after ticket was inserted you wont need to change existing code. Its a major concern and falls under the "Open/Closed Principle" - your code will be closed for modification (maybe you event cannot modify) but open for extension. – Benny67b Nov 06 '21 at 11:30
-
This was the best answer I could find in all the topics. Thank you very much. – Mohsen Movahed Nov 20 '21 at 04:07
-
The EventEmitter should be used when the same event can occur multiple times, or may not occur at all. A callback, in fact, is expected to be invoked exactly once, whether the operation is successful or not. Callback means call me when you are ready
An API that uses callbacks can notify only one particular callback while using an EventEmitter allows us to register multiple listeners for the same event.
Use event emitter if you need to notify the user of a state change.
For testing purpose, if you want to make sure a function is called inside a function, emit an event.

- 35,338
- 10
- 157
- 202
Node.js Event Emitter is used when there is a desire to decompose a codebase into components or services invoked using a pub-sub like asynchronous pattern. However, typically when we talk about pub-sub pattern we refer to distributed decomposed systems. This is not the case here as all components exist in the same code repository and run in the same Node.js runtime.
Keep in mind that using Node.js Event Emitter does not make our code automatically non-blocking, asynchronous. A special care needs to be taken so that event listeners (subscribers) do not block each other, that is the event listeners should execute code asynchronously.
In addition, when using this pattern event emitters (publishers) do not care about the result of the actions taken by the event listeners. There is no callback or return value. If these actions are critical then failures need to be handled.
Code examples:
/**
* When event listeners execute synchronous blocking code as seen in this example,
* the next listener is not notified until the first listener completes execution
* of the synchronous blocking code.
*
* Here is an output from running this code:
*
* 11:16:40 Listener 1 - processing event
* 11:16:45 Listener 1 - processed: Test Event
* 11:16:45 Listener 2 - processing event
* 11:16:45 Listener 2 - processed: Test Event
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', (message) => {
console.log(`${time()} Listener 1 - processing event`);
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');
/**
*
* To take full advantage of EventListener the listeners should execute
* asynchronous non-blocking code. However, wrapping a synchronous code
* into an async function is not enough. The 2nd listener is still
* blocked and waiting for the async function to complete
*
* Here is an output from running this code:
* 11:13:52 Listener 1 - processing event
* 11:13:52 Listener 1 - about to await
* 11:13:57 Listener 2 - processing event
* 11:13:57 Listener 2 - processed: Test Event
* 11:13:57 Listener 1 - await completed
* 11:13:57 Listener 1 - processed: Test Event
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', async (message) => {
console.log(`${time()} Listener 1 - processing event`);
async function extracted() {
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
}
console.log(`${time()} Listener 1 - about to await`);
await extracted();
console.log(`${time()} Listener 1 - await completed`);
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');
/**
*
* To take full advantage of EventListener the listeners should execute
* asynchronous non-blocking code. Here we are using setTimeout() in order
* to execute code asynchronously.
*
* Here is an output from running this code:
*
* 11:45:54 Listener 1 - processing event
* 11:45:54 Listener 1 - about to execute setTimeout
* 11:45:54 Listener 1 - setTimeout completed
* 11:45:54 Listener 1 - processed: Test Event
* 11:45:54 Listener 2 - processing event
* 11:45:54 Listener 2 - processed: Test Event
* 11:45:59 Listener 1 - finished the long loop
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', async (message) => {
console.log(`${time()} Listener 1 - processing event`);
function extracted() {
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
console.log(`${time()} Listener 1 - finished the long loop`);
}
console.log(`${time()} Listener 1 - about to execute setTimeout`);
setTimeout(extracted, 0);
console.log(`${time()} Listener 1 - setTimeout completed`);
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');
/**
*
* To take full advantage of EventListener the listeners should execute
* asynchronous non-blocking code. Here we are using setImmediate() in order
* to execute code asynchronously.
*
* Here is an output from running this code:
*
* 12:1:3 Listener 1 - processing event
* 12:1:3 Listener 1 - about to execute setImmediate
* 12:1:3 Listener 1 - setImmediate completed
* 12:1:3 Listener 1 - processed: Test Event
* 12:1:3 Listener 2 - processing event
* 12:1:3 Listener 2 - processed: Test Event
* 12:1:9 Listener 1 - finished the long loop
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', async (message) => {
console.log(`${time()} Listener 1 - processing event`);
function extracted() {
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
console.log(`${time()} Listener 1 - finished the long loop`);
}
console.log(`${time()} Listener 1 - about to execute setImmediate`);
setImmediate(extracted);
console.log(`${time()} Listener 1 - setImmediate completed`);
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');

- 545
- 7
- 21
-
1"Using async functions with event handlers is problematic, because it can lead to an unhandled rejection in case of a thrown exception" from Node.js official website. – ZenG Jun 09 '23 at 12:35
-
And for long-running block operations, it doesn't matter it's sync or async cause node.js is single threaded. – ZenG Jun 09 '23 at 12:37
-
-
The approach to long-running task in node.js should be handled by worker thread. – ZenG Jun 09 '23 at 12:44