~5 min read • Updated Dec 27, 2025
1. What is EventEmitter?
All objects that emit events are instances of the EventEmitter class. This class provides methods like on() to register listeners and emit() to trigger events.
2. Simple Example
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
3. Passing Arguments and this
emit() can pass arguments to listeners. In regular functions, this refers to the EventEmitter instance. With arrow functions, this does not reference the EventEmitter.
4. Synchronous vs. Asynchronous
Listeners are called synchronously in the order they were registered. To switch to asynchronous execution, use setImmediate() or process.nextTick().
5. One-Time Execution
once() registers a listener that runs only once and is then removed.
6. Error Events
If an EventEmitter emits an 'error' event without a registered listener, Node.js will throw the error and crash. Always register error listeners to prevent this.
myEmitter.on('error', (err) => {
console.error('Error occurred:', err);
});
7. captureRejections
Async listeners can cause unhandled Promise rejections. The captureRejections option routes these rejections to the 'error' event or Symbol.for('nodejs.rejection').
8. Special EventEmitter Events
- 'newListener': Emitted before a new listener is added.
- 'removeListener': Emitted after a listener is removed.
9. Key EventEmitter Methods
on(): Register a listener.once(): Register a one-time listener.emit(): Trigger an event.listeners(): Get a list of listeners.eventNames(): Get registered event names.setMaxListeners(): Set the maximum number of listeners.prependListener(): Add a listener at the beginning of the list.
Conclusion
The Events module is central to Node.js’s event-driven architecture. By using EventEmitter and its methods, developers can build robust asynchronous applications that handle streams, connections, and complex workflows efficiently.
1. prependListener()
Adds a listener to the beginning of the listener array for a given event.
server.prependListener('connection', (stream) => {
console.log('someone connected!');
});
2. prependOnceListener()
Similar to prependListener(), but the listener is invoked only once and then removed.
server.prependOnceListener('connection', (stream) => {
console.log('Ah, we have our first user!');
});
3. removeListener() and removeAllListeners()
removeListener(eventName, listener): Removes a specific listener.removeAllListeners([eventName]): Removes all listeners or all listeners for a specific event.
Note: Removing listeners added by other modules can cause issues and is considered bad practice.
4. setMaxListeners() and defaultMaxListeners
By default, Node.js warns if more than 10 listeners are added to a single event. setMaxListeners(n) changes this limit for a specific instance, while events.defaultMaxListeners changes the default globally.
5. rawListeners()
Returns an array of raw listeners, including wrappers created by methods like once().
const listeners = emitter.rawListeners('log');
listeners[0].listener(); // Executes the original listener without removing it
listeners[0](); // Executes and removes the listener
6. errorMonitor
events.errorMonitor allows monitoring of error events without consuming them. These listeners run before regular error listeners.
7. events.once()
Creates a Promise that resolves when the specified event is emitted, or rejects if an error occurs.
const { once, EventEmitter } = require('node:events');
const ee = new EventEmitter();
(async () => {
const [value] = await once(ee, 'myevent');
console.log(value);
})();
8. Managing Rejections
With captureRejections enabled, rejected Promises in async listeners are automatically routed to the 'error' event or Symbol.for('nodejs.rejection').
Conclusion
Advanced EventEmitter methods in Node.js provide powerful tools for listener management, error handling, and preventing memory leaks. Using these methods correctly enhances the stability and maintainability of event-driven applications.
1. events.listenerCount()
Returns the number of listeners registered for a given event. Deprecated since v3.2.0; use emitter.listenerCount() instead.
const { EventEmitter, listenerCount } = require('node:events');
const myEmitter = new EventEmitter();
myEmitter.on('event', () => {});
myEmitter.on('event', () => {});
console.log(listenerCount(myEmitter, 'event')); // 2
2. events.on()
Creates an AsyncIterator that iterates over emitted events. Each iteration returns an array of arguments passed to the event.
const { on, EventEmitter } = require('node:events');
(async () => {
const ee = new EventEmitter();
process.nextTick(() => {
ee.emit('foo', 'bar');
ee.emit('foo', 42);
});
for await (const event of on(ee, 'foo')) {
console.log(event); // ['bar'], [42]
}
})();
3. events.setMaxListeners()
Sets the maximum number of listeners for one or more EventEmitters or EventTargets. Default is 10, but can be changed globally or per instance.
const { setMaxListeners, EventEmitter } = require('node:events');
const emitter = new EventEmitter();
setMaxListeners(5, emitter);
4. events.addAbortListener()
Safely listens for the abort event on an AbortSignal. Returns a disposable object to easily unsubscribe.
const { addAbortListener } = require('node:events');
function example(signal) {
const disposable = addAbortListener(signal, () => {
console.log('Aborted!');
});
disposable[Symbol.dispose]();
}
5. EventEmitterAsyncResource
Integrates EventEmitter with AsyncResource for manual async tracking. Events emitted by this class run within its async context.
const { EventEmitterAsyncResource } = require('node:events');
const ee = new EventEmitterAsyncResource({ name: 'Q' });
ee.on('foo', () => {
console.log('running in async context');
});
ee.emit('foo');
6. EventTarget and NodeEventTarget
Node.js implements its own EventTarget API, similar to the web standard but with differences:
- No hierarchy or event propagation.
- Listeners can only be registered once per event type.
- NodeEventTarget emulates a subset of EventEmitter methods but is not a full replacement.
const target = new EventTarget();
target.addEventListener('foo', (event) => {
console.log('foo event happened!');
});
target.dispatchEvent(new Event('foo'));
Conclusion
The advanced features of the events module in Node.js provide powerful tools for listener management, async event handling, and integration with AbortSignals and async contexts. Understanding these APIs helps developers build robust, event-driven applications that align with both Node.js and web standards.
Written & researched by Dr. Shahin Siami