The Observer pattern defines a one-to-many dependency: when one object changes state, all dependents are notified. JavaScript's EventEmitter is a built-in implementation of this pattern.
The Observer pattern defines a one-to-many dependency: when one object changes state, all dependents are notified. JavaScript's EventEmitter is a built-in implementation of this pattern.
Observer and Event Emitter is one of the most important topics in Design Patterns in 5 Days. This lesson builds the foundation you need before moving to more advanced concepts — take time with each example and run the code yourself.
// Observer pattern from scratch
interface Observer<T> { update(data: T): void;
}
class EventEmitter<T> { private observers: Observer<T>[] = []; subscribe(observer: Observer<T>) { this.observers.push(observer); return () => this.unsubscribe(observer); // returns unsubscribe fn } unsubscribe(observer: Observer<T>) { this.observers = this.observers.filter(o => o !== observer); } notify(data: T) { this.observers.forEach(o => o.update(data)); }
}
// Usage
const userCreated = new EventEmitter<{ id: number; email: string }>();
userCreated.subscribe({ update: (u) => sendWelcomeEmail(u.email) });
userCreated.subscribe({ update: (u) => addToAnalytics(u.id) });
userCreated.notify({ id: 1, email: '[email protected]' }); // Node.js EventEmitter
import { EventEmitter } from 'node:events';
class OrderService extends EventEmitter { async createOrder(data: OrderData) { const order = await db.orders.create(data); this.emit('order:created', order); return order; }
}
const orders = new OrderService();
orders.on('order:created', (order) => { console.log(\`New order: \${order.id}\`); emailService.sendConfirmation(order.userId);
});
orders.once('order:created', () => { analyticsService.trackFirstOrder();
}); Before moving on, make sure you can answer these without looking: