patternModeratepending
Observer pattern -- decouple event producers from consumers
Viewed 0 times
observerEventEmittersubscribenotifyreactiveevent-driven
Problem
An object needs to notify multiple other objects when its state changes, but should not be tightly coupled to them. Adding a new consumer requires modifying the producer.
Solution
The subject maintains a list of observers and notifies them on state changes. Observers register/unregister themselves. Modern variants: EventEmitter, reactive streams, signals.
Code Snippets
Type-safe event emitter
// TypeScript typed event emitter
type EventMap = {
'user:login': { userId: string; timestamp: number };
'user:logout': { userId: string };
'error': { message: string; code: number };
};
class TypedEmitter<T extends Record<string, any>> {
private listeners = new Map<string, Set<Function>>();
on<K extends keyof T>(event: K, fn: (data: T[K]) => void): () => void {
const set = this.listeners.get(event as string) ?? new Set();
set.add(fn);
this.listeners.set(event as string, set);
return () => set.delete(fn); // unsubscribe
}
emit<K extends keyof T>(event: K, data: T[K]): void {
this.listeners.get(event as string)?.forEach(fn => fn(data));
}
}
const bus = new TypedEmitter<EventMap>();
const unsub = bus.on('user:login', ({ userId }) => {
console.log(`Welcome ${userId}`);
});
bus.emit('user:login', { userId: '42', timestamp: Date.now() });
unsub(); // cleanupRevisions (0)
No revisions yet.