2694. Event Emitter

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 - This method takes in two arguments: the name of an event as a string and a callback function. This callback function will later be called when the event is emitted.
    An event should be able to have multiple listeners for the same event. When emitting an event with multiple callbacks, each should be called in the order in which they were subscribed. An array of results should be returned. You can assume no callbacks passed to subscribe are referentially identical.
    The 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.

  • emit - This method takes in two arguments: the name of an event as a string and an optional array of arguments that will be passed to the callback(s). If there are no callbacks subscribed to the given event, return an empty array. Otherwise, return an array of the results of all callback calls in the order they were subscribed.

 

Example 1:

Example 2:

Example 3:

Constraints:

  • 1 <= actions.length <= 10
  • values.length === actions.length
  • All test cases are valid, e.g. you don’t need to handle scenarios when unsubscribing from a non-existing subscription.
  • There are only 4 different actions: EventEmitter, emit, subscribe, and unsubscribe.
  • The EventEmitter action doesn’t take any arguments.
  • The 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.
  • The subscribe action takes 2 arguments, where the first one is the event name and the second is the callback function.
  • The unsubscribe action takes one argument, which is the 0-indexed order of the subscription made before.

From: LeetCode
Link: 2694. Event Emitter


Solution:

Ideas:
The idea behind the code is to create a generic event emitter class that can be used to emit events and subscribe to them. The class has two main methods: subscribe and emit.
The subscribe method takes in two arguments: the name of the event and a callback function. The callback function will be called when the event is emitted. The emit method takes in two arguments: the name of the event and an optional array of arguments that will be passed to the callback function.
The class also has a private method called _unsubscribe. This method is used to unsubscribe from an event. When a callback function is unsubscribed, it will no longer be called when the event is emitted.
The code is designed to be generic and reusable. It can be used to create any type of event emitter, such as a DOM event emitter or a Node.js event emitter.
Here is a more detailed explanation of the code:
  • The constructor method initializes the class. It creates an empty object to store the subscriptions.
  • The subscribe method adds a callback function to the list of subscriptions for the given event. It returns an object that has an unsubscribe method.
  • The _unsubscribe method removes a callback function from the list of subscriptions for the given event.
  • The emit method calls the callback functions for the given event. It passes the optional array of arguments to the callback functions.
Code:
class EventEmitter {
  constructor() {
    this._subscriptions = {};
  }

  subscribe(event, cb) {
    if (!this._subscriptions[event]) {
      this._subscriptions[event] = [];
    }

    this._subscriptions[event].push(cb);

    return {
      unsubscribe: () => {
        this._unsubscribe(event, cb);
      }
    };
  }

  _unsubscribe(event, cb) {
    const subscriptions = this._subscriptions[event];

    if (subscriptions) {
      const index = subscriptions.indexOf(cb);

      if (index >= 0) {
        subscriptions.splice(index, 1);
      }
    }
  }

  emit(event, args = []) {
    const subscriptions = this._subscriptions[event];

    if (subscriptions) {
      const results = [];

      for (const cb of subscriptions) {
        results.push(cb(...args));
      }

      return results;
    } else {
      return [];
    }
  }
}

/**
 * const emitter = new EventEmitter();
 *
 * // Subscribe to the onClick event with onClickCallback
 * function onClickCallback() { return 99 }
 * const sub = emitter.subscribe('onClick', onClickCallback);
 *
 * emitter.emit('onClick'); // [99]
 * sub.unsubscribe(); // undefined
 * emitter.emit('onClick'); // []
 */
05-31 13:35