Observer pattern and Pub/Sub pattern in JS

Vishal Gupta
3 min readOct 12, 2022

--

Here I am going to illustrate observer pattern first and its code walk through and then comes to Pub/Sub pattern

Below is a simple implementation of the observer pattern:

function Subject () {
this.observers = [];
}

Subject.prototype = {
getIndex: function(observer) {
return this.observers.indexOf(observer)
},
subscribe: function(observer) {
this.observers.push(observer);
},
unsubscribe: function(observer) {
this.observers = this.observers.filter(item => item !== observer)
},
notify: function (observer) {
let observerIndex = this.getIndex(observer);
if(observerIndex > -1) {
this.observers[observerIndex].notify(observerIndex);
}
},
notifyAll: function () {
this.observers.forEach((observer) => {
observer.notify();
})
},
count: function () {
return this.observers.length;
}
}

function Observer (id) {
return {
id,
notify: function() {
console.log(`Observer ${id} has been notified!`)
}
}
}

const subject = new Subject();
const observer1 = new Observer(1);
const observer2 = new Observer(2);


subject.subscribe(observer1);
subject.subscribe(observer2);

subject.notifyAll() // prints
// Observer 1 has been notified!
// Observer 2 has been notified!

subject.unsubscribe(observer1);
subject.count() // prints 1
subject.notify(observer2) // prints
// Observer 2 has been notified!

In the code above, the Subject constructor maintains a list of observers. And we added the relevant methods to the prototype of the Subject. This enables us to share these methods with every instance of the Subject.

If you do not understand how we can share methods using an object’s prototype, I suggest you read a previous article that covers prototypal inheritance in JavaScript.

In the code above, the subscribe method adds observers to the observers array while the unsubscribe method removes observers from the observers array. The notify method would notify the specified subscribed observer while the notifyAll method notifies all the subscribed observers.

PUB/SUB PATTERN:

The pub/sub broker also enables loose decoupling of publishers and subscribers and it supports many to many relationships between the publishers and the subscribers.

So unlike the observer pattern, the pub/sub pattern allows multiple publishers and multiple subscribers.

In the pub/sub pattern a publisher publishes contents to a topic and interested subscribers access these contents by sending subscriptions to the pub/sub broker to subscribe to that topic. Also, unlike the observer pattern, both the publishers and the subscribers do not need to be aware of each other.

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

subscription (eventName, func) {
return {
subscribe: () => {
if (this.events[eventName]) {
this.events[eventName].push(func);
console.log(`${func.name} has subscribed to ${eventName} Topic!`)
} else {
this.events[eventName] = [func];
console.log(`${func.name} has subscribed to ${eventName} Topic!`)
}
},

unsubscribe: () => {
if(this.events[eventName]){
this.events[eventName] = this.events[eventName].filter((subscriber) => subscriber !== func);
console.log(`${func.name} has unsubscribed from ${eventName} Topic!`)
}
}


}
}


publish(eventName, ...args) {
const funcs = this.events[eventName];
if (Array.isArray(funcs)) {
funcs.forEach((func) => {
func.apply(null, args);
});
}
}
}

const speak = (param) => {
console.log(`I am ${param}`);
};

const greetAll = (x, y, z) => {
console.log(`Hello ${x}, ${y}, ${z}`);
};

const pubsub = new Pubsub();


pubsub.subscription("greet", greetAll).subscribe() // prints greetAll has subscribed to greet Topic!

pubsub.subscription("sayName", speak).subscribe() // prints speak has subscribed to sayName Topic!
pubsub.subscription("sayName", greetAll).unsubscribe() // prints greetAll has unsubscribed from sayName Topic!



pubsub.publish("greet", "Lawrence Eagles", "John Doe", "Jane Doe"); // prints Hello Lawrence Eagles, John Doe, Jane Doe

pubsub.publish("sayName", "Lawrence Eagles"); // prints I am Lawrence Eagles

In our small example above, the subscription method returns an object containing a subscribe method used to handle subscriptions and an unsubscribe method that handles unsubscriptions.

Some examples of real-life applications that use the pub/sub pattern are Redis, Split, Twillo, and Gutenberg created by Netflix.

--

--

Vishal Gupta
Vishal Gupta

No responses yet