Implement a chainable EventEmitter with on, off, and emit
Implement an EventEmitter class with on(event, fn), off(event, fn), and emit(event, ...args). Requirements: emit calls every registered listener for the event with the forwarded args; on/off return this for chaining; a listener that throws must not stop the others from running.
class EventEmitter {
// your code here
}
Write the implementation.
Keep a Map from event name to a Set of listeners. on adds the listener and returns this; off deletes it and returns this. emit iterates a copy of the listener set, wrapping each call in try/catch so one throwing listener does not abort the rest. Copying before iterating also makes it safe to add or remove listeners during emit.
- ✗Letting one throwing listener abort the rest instead of isolating each call
- ✗Iterating the live listener collection, breaking add/remove during emit
- ✗Forgetting to return
thisfromon/off, which breaks chaining
- →How would you add a
once(event, fn)that auto-removes after the first emit? - →Why copy the listener set before iterating it inside
emit?
Solution
A Map of event names to a Set of listeners, with error isolation and this return.
class EventEmitter {
#listeners = new Map();
on(event, fn) {
if (!this.#listeners.has(event)) this.#listeners.set(event, new Set());
this.#listeners.get(event).add(fn);
return this;
}
off(event, fn) {
this.#listeners.get(event)?.delete(fn);
return this;
}
emit(event, ...args) {
const set = this.#listeners.get(event);
if (!set) return false;
for (const fn of [...set]) { // copy: safe under on/off during emit
try { fn(...args); }
catch (err) { console.error(err); } // isolation: one failure does not break the rest
}
return true;
}
}
How it works
A Set per event automatically dedups listeners and gives O(1) delete. emit iterates a copy of the set, so a listener that calls on/off mid-dispatch does not break the iteration. Each call is wrapped in try/catch, so a thrown error is isolated and the remaining listeners still run. on and off return this, enabling bus.on(...).on(...) chaining.