• Prefrences

    Select a theme

Publisher-Subscriber(pub-Sub) pattern in Javascript

Publisher Subscriber(Pub-Sub) pattern goes further ahead by decoupling the registration process of subscribers and publishers compared to Observer pattern . It introduces a message broker or Event Bus which acts as a bridge between a publisher(Subject) and various Subscribers. The topics are published by Subject for different kinds of events. The subscriber registers for the respective topics to get notified.

Let me try an analogy for it:

lets say we have 10 radio stations in a city. Each radio station works at their own frequency In case we want to listen to radio station(A) with frequency equal to 100, we have to switch to the given frequency. Radio station(A) publishes its episodes at the frequency(topic/event) 100. As a subscriber, if we want to listen to it, we have to listen at this frequency(topic/event)

pubsub-analogy

Lets implement the publisher subscriber design pattern using Javascript.

Create an Event Bus object which has the registration and publishing API

	
    var EventBus = function(){
    var eventTopics =  {};
    
    this.addEventListener =  function (eventName, listener) {
        if ( !eventTopics[eventName] || eventTopics[eventName].length < 1) {
                eventTopics[eventName] = [];
        }
         eventTopics[eventName].push(listener);
    };
   
    this.emitEventListeners = function (eventName , params) {
        if ( !eventTopics[eventName] || eventTopics[eventName].length < 1) return;
          eventTopics[eventName].forEach(function (listener) {
            listener( !!params ? params : {} );
        });
    }
    
} //END EventBus

addEventListener and emitEventListeners functions lets the subscriber and publisher to subscribe and publish on events respectively.

An EventBus can be used as an independent object for registration and publishing such as

//initialize the event bus
var EventService = new EventBus();
//add the event listener
EventService.addEventListener('SEND', callback1);
EventService.addEventListener('SEND', callback2);

var EmailService = {
	createEmail = function(to, from, subject){
		//some business here
		EventService.emitEventListeners('SEND' , subject);
	} 
}

we can also let EmailService extend EventBus. This would make EmailService have all the characteristics of EventBus. Based on the need, we can customize the API also.

//extend the EventBus
var EmailService = function(){
  EventBus.call(this);
  this.createEmail = function(to, from, subject){
      //send the email
      //publish/emit the event = order/new 
      this.emitEventListeners('SEND',Subject)
 }
}
EmailService.prototype = Object.create(EventBus.prototype)
EmailService.prototype.constructor = EmailService;

Note: you can use the new features of ES6 classes to extend to the EventBus object

Now that we have extended to EventBus. lets create the EmailService Object

	var emailService = new EmailService();
	emailService.addEventListener('SEND', callback);

When a business service extends to the EventBus. It makes it representational while keeping the benefits of decoupling and customization. For example: In a different module, if I want to add a listener to SEND Event . I can do either

	  EventBus.addEventListener('SEND', callback)

or

	 EmailService.addEventListener('SEND',callback)

As you notice, in the later case it is very clear to what purpose and service are we subscribing to.

checkout the complete example in the below pen

See the Pen pub-sub js by s://irshad:ahmad.(sheikh) (@igagrock) on CodePen.

If you have any feedback, let me know in the comments below and don't forget to give a thumbs up.