Katkat

Implement an event emitter

SnowflakeFrontend Engineer · Technical Screen

Last updated

This problem tests your understanding of the observer pattern, internal state management using maps, and the ability to handle edge cases in listener lifecycle management.

Event Emitter Implementation

Design an EventEmitter class that manages event subscriptions. Your implementation should allow users to subscribe to events, emit events with optional data, and unsubscribe from specific events.

Requirements

  • on(eventName, callback): Adds a listener function to the specified event. If multiple listeners are added for the same event, they should be invoked in the order they were added.
  • off(eventName, callback): Removes a specific listener for the specified event.
  • emit(eventName, ...args): Invokes all listeners subscribed to the eventName, passing the provided arguments to each.
  • If an emit occurs for an event with no listeners, it should do nothing.

Example

const emitter = new EventEmitter();

function greet(name) { console.log(`Hello, ${name}!`); }

emitter.on('greet', greet);
emitter.emit('greet', 'Alice'); // Prints: "Hello, Alice!"

emitter.off('greet', greet);
emitter.emit('greet', 'Bob');   // Nothing happens

Constraints

  • You may assume eventName is always a string.
  • The callback will always be a function.
  • Efficiency matters: off should ideally run in better than linear time relative to total listeners.

Edge Cases

  • Removing a listener that was never added.
  • Emitting an event before any listeners are added.
  • Adding/removing the same listener function multiple times for the same event.

Hints

Hint 1

Use a JavaScript object or a Map to store event names as keys and an array of callback functions as the corresponding values.

Hint 2

For the 'off' method, you can use Array.prototype.filter() or indexOf/splice to remove the specific callback instance from the array.

Hint 3

Consider how you would handle multiple identical callbacks being added to the same event—should 'off' remove all instances or just the first one?

Follow-up questions

  • How would you modify your implementation to support an 'once(eventName, callback)' method, which triggers the listener only once before being automatically removed?
  • What are the performance implications of using an array to store callbacks versus a Set if the order of execution is not guaranteed?
  • How would you modify the 'emit' method to handle cases where a listener throws an error, ensuring that other listeners for the same event still execute?