Creating an Event Emitter in JavaScript with Pub/Sub: A Comprehensive Guide

Creating an Event Emitter in JavaScript with Pub/Sub: A Comprehensive Guide

·

4 min read

Events play a crucial role in JavaScript, allowing developers to create interactive and responsive applications. One powerful pattern for managing events is the Publisher-Subscriber (Pub/Sub) pattern. In this blog post, we'll explore how to create an Event Emitter in JavaScript using the Pub/Sub pattern, providing a robust foundation for managing and handling events in your applications.

Understanding the Pub/Sub Pattern:

The Pub/Sub pattern is a behavioral design pattern that enables a system to communicate between various components without them being directly aware of each other. In the context of events, the Publisher (the sender) emits events, and Subscribers (listeners) subscribe to specific events of interest. This decoupling ensures a flexible and scalable architecture.

To get started, create a new JavaScript file and set up a basic structure. You can use this as a standalone module or incorporate it into your existing project.

// eventEmitter.js
class EventEmitter {
  constructor() {
    this.subscribers = {};
  }

  subscribe(event, callback) {
    if (!this.subscribers[event]) {
      this.subscribers[event] = [];
    }
    this.subscribers[event].push(callback);
  }

  unsubscribe(event, callback) {
    if (this.subscribers[event]) {
      this.subscribers[event] = this.subscribers[event].filter(sub => sub !== callback);
    }
  }

  emit(event, data) {
    if (this.subscribers[event]) {
      this.subscribers[event].forEach(sub => sub(data));
    }
  }
}

// Example Usage
const myEventEmitter = new EventEmitter();

const callback1 = data => {
  console.log(`Callback 1 executed with data: ${data}`);
};

const callback2 = data => {
  console.log(`Callback 2 executed with data: ${data}`);
};

myEventEmitter.subscribe('customEvent', callback1);
myEventEmitter.subscribe('customEvent', callback2);

myEventEmitter.emit('customEvent', 'Hello, Pub/Sub!');
// Output:
// Callback 1 executed with data: Hello, Pub/Sub!
// Callback 2 executed with data: Hello, Pub/Sub!

myEventEmitter.unsubscribe('customEvent', callback1);

myEventEmitter.emit('customEvent', 'Event after unsubscribing');
// Output:
// Callback 2 executed with data: Event after unsubscribing

Let's break down the code for creating an Event Emitter in JavaScript using the Pub/Sub pattern step by step:

EventEmitter Class:

constructor() {
  this.subscribers = {};
}

The EventEmitter class has a constructor that initializes an empty object called subscribers. This object will be used to store events and their corresponding subscribers.

subscribe Method:

subscribe(event, callback) {
  if (!this.subscribers[event]) {
    this.subscribers[event] = [];
  }
  this.subscribers[event].push(callback);
}

The subscribe method allows subscribers to register their interest in a specific event.

If the specified event does not exist in the subscribers object, a new array is created for that event. The callback function is then added to the array of subscribers for the given event.

unsubscribe Method:

unsubscribe(event, callback) {
  if (this.subscribers[event]) {
    this.subscribers[event] = this.subscribers[event].filter(sub => sub !== callback);
  }
}

The unsubscribe method enables subscribers to unregister their interest in a particular event.

If the specified event exists in the subscribers object, the method filters out the callback that needs to be unsubscribed from the array of subscribers for that event.

emit Method:

emit(event, data) {
  if (this.subscribers[event]) {
    this.subscribers[event].forEach(sub => sub(data));
  }
}
  • The emit method triggers the execution of all subscribed callbacks for a given event.

  • If the specified event exists in the subscribers object, it iterates through the array of callbacks for that event and executes each callback, passing the provided data as an argument.

Example Usage:

const myEventEmitter = new EventEmitter();

const callback1 = data => {
  console.log(`Callback 1 executed with data: ${data}`);
};

const callback2 = data => {
  console.log(`Callback 2 executed with data: ${data}`);
};

myEventEmitter.subscribe('customEvent', callback1);
myEventEmitter.subscribe('customEvent', callback2);

myEventEmitter.emit('customEvent', 'Hello, Pub/Sub!');
// Output:
// Callback 1 executed with data: Hello, Pub/Sub!
// Callback 2 executed with data: Hello, Pub/Sub!

// now we are unsubscribing the callback1 from 'customEvent',
// callback1 will not be executed any more on this event
myEventEmitter.unsubscribe('customEvent', callback1);


myEventEmitter.emit('customEvent', 'Event after unsubscribing');
// Output:
// Callback 2 executed with data: Event after unsubscribing
  • An instance of the EventEmitter class (myEventEmitter) is created.

  • Two callback functions (callback1 and callback2) are defined.

  • Both callbacks are subscribed to the 'customEvent' using the subscribe method.

  • The emit method is used to trigger the execution of subscribed callbacks for the 'customEvent' with the provided data.

  • The unsubscribe method is then used to remove callback1 from the subscribers for the 'customEvent'.

  • Finally, another emit demonstrates that only callback2 is executed after unsubscribing callback1.

Did you find this article valuable?

Support Md Talha by becoming a sponsor. Any amount is appreciated!