Introduction
The events module exposes the EventEmitter class, which implements the observer (publish/subscribe) pattern at the core of Node.js. Many built-in objects — HTTP servers, streams, and process — are EventEmitters. An EventEmitter object emits named events, and any number of listener functions can be registered to run when a specific event fires. This decouples the code that triggers an action from the code that reacts to it.
Cricket analogy: The stadium PA system is an EventEmitter: it announces 'WICKET!' and the scoreboard, commentary box, and giant screen all react independently without the bowler needing to know who is listening.
Syntax
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter();
emitter.on('eventName', (arg1, arg2) => {
// listener logic
});
emitter.emit('eventName', arg1, arg2);
emitter.once('eventName', listener); // fires only once
emitter.off('eventName', listener); // removes a listenerExplanation
emitter.on(eventName, listener) registers a listener function to be called every time the named event is emitted. emitter.emit(eventName, ...args) synchronously invokes all listeners registered for that event, passing along any arguments. emitter.once(eventName, listener) registers a listener that automatically removes itself after being called one time, which is useful for one-off notifications. emitter.off(eventName, listener) (or removeListener) unregisters a previously added listener. By convention, if an emitter emits an 'error' event with no listener attached, Node throws the error and can crash the process, so error events should always have a handler.
Cricket analogy: emitter.on is like a fan subscribing to every ball-by-ball update for the whole match; emitter.once is like subscribing only to the toss announcement, which fires and then unsubscribes itself.
Example
const EventEmitter = require('events');
class OrderProcessor extends EventEmitter {
placeOrder(orderId, amount) {
console.log(`Processing order ${orderId}...`);
this.emit('orderPlaced', orderId, amount);
}
}
const processor = new OrderProcessor();
processor.on('orderPlaced', (orderId, amount) => {
console.log(`Order ${orderId} placed for $${amount}`);
});
processor.once('orderPlaced', () => {
console.log('Sending confirmation email (only once)...');
});
processor.placeOrder('A1001', 49.99);
processor.placeOrder('A1002', 15.5);Output
Running the example prints: 'Processing order A1001...', 'Order A1001 placed for $49.99', 'Sending confirmation email (only once)...', then 'Processing order A1002...', 'Order A1002 placed for $15.5'. Note that the 'once' listener only fires for the first emit call; it does not run again for the second order because it removed itself after the first invocation.
Cricket analogy: It's like a commentator announcing the toss only at the very start of the match, then only reporting scores for every subsequent over, never repeating the toss announcement again.
Key Takeaways
- EventEmitter implements the observer pattern: emit() triggers all registered listeners for an event synchronously.
- on() registers a persistent listener; once() registers a listener that auto-removes after firing one time.
- off()/removeListener() unregisters a listener when it's no longer needed.
- Custom classes commonly extend EventEmitter to broadcast their own domain events.
- Unhandled 'error' events on an EventEmitter will throw and can crash the Node process, so always attach an error listener.
Practice what you learned
1. Which class provides the observer pattern implementation in Node.js core?
2. What is the difference between emitter.on() and emitter.once()?
3. What happens if an EventEmitter emits an 'error' event with no listeners attached?
4. How do you trigger all listeners registered for a given event?
Was this page helpful?
You May Also Like
Callbacks in Node.js
How Node.js uses callback functions to handle asynchronous operations without blocking the main thread.
Streams in Node.js
Processing data piece by piece with Readable, Writable, Duplex, and Transform streams, including backpressure handling.
Node.js Architecture and the Event Loop
Understand Node.js's single-threaded, non-blocking architecture and how the event loop phases process callbacks.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics