Design an EventEmitter class. This interface is similar (but with some differences) to the one found in Node.js or the Event Target interface of the DOM. The EventEmitter should allow for subscribing to events and emitting them.
Your EventEmitter class should have the following two methods:
subscribe are referentially identical.subscribe method should also return an object with an unsubscribe method that enables the user to unsubscribe. When it is called, the callback should be removed from the list of subscriptions and undefined should be returned.
Example 1:
Input:
actions = ["EventEmitter", "emit", "subscribe", "subscribe", "emit"],
values = [[], ["firstEvent"], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent", "function cb1() { return 6; }"], ["firstEvent"]]
Output: [[],["emitted",[]],["subscribed"],["subscribed"],["emitted",[5,6]]]
Explanation:
const emitter = new EventEmitter();
emitter.emit("firstEvent"); // [], no callback are subscribed yet
emitter.subscribe("firstEvent", function cb1() { return 5; });
emitter.subscribe("firstEvent", function cb2() { return 6; });
emitter.emit("firstEvent"); // [5, 6], returns the output of cb1 and cb2
Example 2:
Input:
actions = ["EventEmitter", "subscribe", "emit", "emit"],
values = [[], ["firstEvent", "function cb1(...args) { return args.join(','); }"], ["firstEvent", [1,2,3]], ["firstEvent", [3,4,6]]]
Output: [[],["subscribed"],["emitted",["1,2,3"]],["emitted",["3,4,6"]]]
Explanation: Note that the emit method should be able to accept an OPTIONAL array of arguments.
const emitter = new EventEmitter();
emitter.subscribe("firstEvent, function cb1(...args) { return args.join(','); });
emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"]
emitter.emit("firstEvent", [3, 4, 6]); // ["3,4,6"]
Example 3:
Input:
actions = ["EventEmitter", "subscribe", "emit", "unsubscribe", "emit"],
values = [[], ["firstEvent", "(...args) => args.join(',')"], ["firstEvent", [1,2,3]], [0], ["firstEvent", [4,5,6]]]
Output: [[],["subscribed"],["emitted",["1,2,3"]],["unsubscribed",0],["emitted",[]]]
Explanation:
const emitter = new EventEmitter();
const sub = emitter.subscribe("firstEvent", (...args) => args.join(','));
emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"]
sub.unsubscribe(); // undefined
emitter.emit("firstEvent", [4, 5, 6]); // [], there are no subscriptions
Example 4:
Input:
actions = ["EventEmitter", "subscribe", "subscribe", "unsubscribe", "emit"],
values = [[], ["firstEvent", "x => x + 1"], ["firstEvent", "x => x + 2"], [0], ["firstEvent", [5]]]
Output: [[],["subscribed"],["subscribed"],["unsubscribed",0],["emitted",[7]]]
Explanation:
const emitter = new EventEmitter();
const sub1 = emitter.subscribe("firstEvent", x => x + 1);
const sub2 = emitter.subscribe("firstEvent", x => x + 2);
sub1.unsubscribe(); // undefined
emitter.emit("firstEvent", [5]); // [7]
Constraints:
1 <= actions.length <= 10values.length === actions.lengthEventEmitter, emit, subscribe, and unsubscribe.EventEmitter action doesn't take any arguments.emit action takes between either 1 or 2 arguments. The first argument is the name of the event we want to emit, and the 2nd argument is passed to the callback functions.subscribe action takes 2 arguments, where the first one is the event name and the second is the callback function.unsubscribe action takes one argument, which is the 0-indexed order of the subscription made before.This approach uses a HashMap (or similar data structure) to maintain a list of listeners (callbacks) for each event. When an event is emitted, we iterate through the list of registered callbacks and invoke them. This list enables easy addition and removal of callbacks (for unsubscribe functionality) and supports ordered invocation on event emission.
The EventEmitter class contains a subscribe method to add event listeners to a dictionary, with event names as keys and arrays of callbacks as values. The emit method retrieves the listener list for a given event and executes each callback with provided arguments, returning an array of results. The unsubscribe feature is implemented by removing a callback from the array using an index.
Python
Java
C++
C#
C
Time Complexity: O(n) for emit, where n is the number of callbacks for the event. O(1) for subscribe and unsubscribe.
Space Complexity: O(m), where m is the number of events and subscribed callbacks.
This approach employs the Observer pattern, common in design paradigms where a subject maintains a list of observers that react to state changes or events. In this context, the EventEmitter represents the Subject, and listeners are Observers.
In this JavaScript solution, the Observer class holds the callback function. The notify method executes the callback. EventEmitter manages observers, allowing subscriptions by creating Observer instances and using their notify methods in emit calls.
Python
Time Complexity: O(n) for notifying listeners (n is the number of listeners).
Space Complexity: O(m), where m consists of stored observers.
| Approach | Complexity |
|---|---|
| Approach 1: Using a HashMap for Event Listeners | Time Complexity: O(n) for emit, where n is the number of callbacks for the event. O(1) for subscribe and unsubscribe. |
| Approach 2: Using Observer Pattern | Time Complexity: O(n) for notifying listeners (n is the number of listeners). |
The LeetCode Fallacy • NeetCode • 628,353 views views
Watch 9 more video solutions →Practice Event Emitter with our built-in code editor and test cases.
Practice on FleetCode