We use cookies (including Google cookies) to personalize ads and analyze traffic. By continuing to use our site, you accept our Privacy Policy.

Event Emitter

Difficulty: Medium


Problem Description

Design an EventEmitter class that allows for subscribing to events and emitting them. The class should support multiple listeners for the same event, maintain the order of callbacks, and provide an unsubscribe method.


Key Insights

  • The EventEmitter should manage subscriptions using a dictionary where events map to arrays of callback functions.
  • Each subscription should return an object containing an unsubscribe method to remove the listener.
  • The emit method should call all registered callbacks for a specific event and return their results.
  • Handle edge cases where no listeners are registered for an event.

Space and Time Complexity

Time Complexity: O(n) for emitting events, where n is the number of subscribers to the event. O(1) for subscribing and unsubscribing. Space Complexity: O(n) for storing the event listeners.


Solution

The EventEmitter class uses a dictionary (or map) to store events and their associated listeners. When a listener is added via the subscribe method, it appends the callback to an array corresponding to the event name. The emit method retrieves the array of callbacks for a given event and calls each one, collecting their return values in an array that is returned to the caller. The unsubscribe method removes a specific callback based on its index.


Code Solutions

class EventEmitter {
    constructor() {
        this.events = {};
    }

    subscribe(event, callback) {
        // Initialize the event if it doesn't exist
        if (!this.events[event]) {
            this.events[event] = [];
        }
        
        // Add the callback to the event's listener array
        this.events[event].push(callback);
        
        // Return an object with an unsubscribe method
        return {
            unsubscribe: () => {
                this.events[event] = this.events[event].filter(cb => cb !== callback);
                return undefined;
            }
        };
    }

    emit(event, args = []) {
        // If there are no listeners for the event, return an empty array
        if (!this.events[event] || this.events[event].length === 0) {
            return [];
        }
        
        // Call each listener and collect their return values
        return this.events[event].map(callback => callback(...args));
    }
}
← Back to All Questions