Events & the EventEmitter
Node.js is fundamentally event-driven. The EventEmitter class is the backbone of Node's event system — almost every built-in module (HTTP, Streams, File System) extends it to emit and listen for named events.
1 Creating & Using EventEmitter
JavaScript — EventEmitter Basics
const { EventEmitter } = require('events');
// Create an emitter instance
const emitter = new EventEmitter();
// Register a listener for 'data' event
emitter.on('data', (payload) => {
console.log('Data received:', payload);
});
// One-time listener (fires only once, then auto-removed)
emitter.once('connect', (host) => {
console.log('Connected to:', host);
});
// Emit events with payloads
emitter.emit('data', { id: 1, value: 42 });
emitter.emit('connect', 'database.server.com');
emitter.emit('connect', 'second.server.com'); // ignored — once() already fired
// Remove a specific listener
const handler = (msg) => console.log(msg);
emitter.on('message', handler);
emitter.off('message', handler); // removes it
2 Custom Event Classes
Best practice is to extend EventEmitter to create typed event sources:
JavaScript — Custom EventEmitter class
const { EventEmitter } = require('events');
class TaskQueue extends EventEmitter {
constructor() {
super();
this.tasks = [];
}
addTask(task) {
this.tasks.push(task);
this.emit('taskAdded', task);
}
processNext() {
if (this.tasks.length === 0) {
this.emit('empty');
return;
}
const task = this.tasks.shift();
this.emit('processing', task);
// ... process task
this.emit('done', task);
}
}
const queue = new TaskQueue();
queue.on('taskAdded', t => console.log('Added task:', t.name));
queue.on('done', t => console.log('Completed:', t.name));
queue.on('empty', () => console.log('Queue is empty.'));
queue.addTask({ name: 'Send Email', priority: 1 });
queue.processNext();
3 Code Challenge
Challenge: Build a
Logger class extending EventEmitter that emits 'info', 'warn', and 'error' events. Register listeners that format and print each log level with a timestamp prefix.