पाठ 17 / 25
Observer, Pub/Sub and Event Emitters
Notify many listeners without knowing them.
Subjects and subscribers
Intent: define a one-to-many dependency so that when a subject changes, all its observers are notified automatically. The subject keeps a list of listeners and calls them; it does not know what they do. This decouples, for example, an OrderService from the email, analytics and loyalty modules that react to "order placed". Variants: Node.js EventEmitter and the DOM EventTarget (in-process events), pub/sub with a broker in between (Redis, Kafka, cloud queues), and reactive streams (RxJS observables). Watch out for memory leaks from listeners that are never removed, hard-to-trace control flow ("who reacts to this event?"), and error handling: decide whether one failing listener should affect others.
A typed event bus
Listeners subscribe and receive an unsubscribe function.
type Events = {
'order.placed': { orderId: string; customerEmail: string; totalCents: number };
'order.cancelled': { orderId: string; reason: string };
};
class EventBus<E extends Record<string, unknown>> {
private listeners: { [K in keyof E]?: Array<(payload: E[K]) => void> } = {};
on<K extends keyof E>(event: K, fn: (payload: E[K]) => void): () => void {
(this.listeners[event] ??= []).push(fn);
return () => { this.listeners[event] = this.listeners[event]!.filter((f) => f !== fn); };
}
emit<K extends keyof E>(event: K, payload: E[K]) {
for (const fn of this.listeners[event] ?? []) {
try { fn(payload); } catch (err) { logger.error({ err, event }, 'listener failed'); }
}
}
}
const bus = new EventBus<Events>();
bus.on('order.placed', (e) => mailer.sendReceipt(e.customerEmail, e.orderId));
bus.on('order.placed', (e) => analytics.track('purchase', { value: e.totalCents }));
const unsubscribe = bus.on('order.cancelled', (e) => inventory.restock(e.orderId));
bus.emit('order.placed', { orderId: 'o-1', customerEmail: 'asha@example.com', totalCents: 2599 });Always keep the unsubscribe
In UI code, subscribe in a mount or effect hook and unsubscribe in its cleanup; forgetting this is a classic source of leaks and duplicate handlers.
त्वरित जाँच: What is a common pitfall of the Observer pattern?
- It cannot have more than one observer
- It requires a database
- Listeners that are never removed, causing memory leaks or duplicate handling
- It forces synchronous network calls
Answer
Listeners that are never removed, causing memory leaks or duplicate handling — Subscriptions need a lifecycle.