DEV Community

Cover image for Design Pattern #4 - Publisher/Subscriber Pattern
Vitor Norton for SuperViz

Posted on • Updated on • Originally published at superviz.com

Design Pattern #4 - Publisher/Subscriber Pattern

In the previously article of this series I covered about the Observer Pattern. Today, I want to share with you the Publisher and Subscriber pattern, or the PubSub for the closest friends. I highly recommend reading and understanding the Observer Pattern before continuing this quest.

Pub Sub Pattern Design

The PubSub Pattern is a messaging pattern that promotes loose coupling and scalability. This pattern revolves around dispatching messages from publishers to an unspecified number of subscribers or listeners, thereby promoting a many-to-many dependency between objects.

Real case scenario

Let’s consider a chat group application. The Pub/Sub system can handle the sending and receiving of messages efficiently:

Subscribing to a event

When a chat window is opened, it subscribes to an event, such as newMessage.

This is done using pubsub.subscribe("newMessage", callback). The callback function is what will be executed when a new message is published to the newMessage event. In this case, the callback logs the new message and updates the chat UI.

pubsub.subscribe("newMessage", function(data) {
    console.log("New message received:", data);
    // Here you would update the chat UI with the new message
});
Enter fullscreen mode Exit fullscreen mode

Publishing to a event

When a user sends a message, it is published to the newMessage event using pubsub.publish("newMessage", messageData). All chat windows subscribed to the newMessage topic will have their callback functions executed with the new message as the argument.

When a user sends a message, it's published to the newMessage event using pubsub.publish("newMessage", messageData). All chat windows subscribed to the newMessage topic will have their callback functions executed with the new message as the argument.

const messageData = { user: "User A", text: "This is what the user had typed" };

pubsub.publish("newMessage", messageData);
Enter fullscreen mode Exit fullscreen mode

In this way, the Pub/Sub system allows for the decoupling of chat windows (subscribers) and message senders (publishers). The chat windows don't need to know about who sends messages (like we saw on the previously post about the observer pattern), they just need to know what to do when a message is received.

Similarly, message senders don’t need to know who will receive the messages; they just need to send messages to the right topic.

How to build a pub sub

To construct a PubSub system, we need to maintain a record of events or 'topics' and their respective subscribers. This can be done with a simple JavaScript object. When a new message is published, we look up the associated subscribers and execute their callback functions. This allows for a dynamic and flexible system where publishers and subscribers can be added or removed at runtime.

class PubSub {
        static events = {}; // It has the an empty list of events

    // The subscribe method takes an event name and a callback function
    subscribe(eventName, callback) {
        if (!this.events[eventName]) {
                // If the event doesn't exist yet, initialize it as an empty array
            this.events[eventName] = [];
        }

        // Push the callback function into the array of callbacks for the given event
        this.events[eventName].push(callback);
    }

    // The publish method takes an event name and data
    publish(event, data) {
        // If the event doesn't exist, or there's no subscribers for this event, return
        if (!this.events[event]) {
            return;
        }

        // For each subscriber of this event, call the callback function with the provided data
        this.events[event].forEach((callback) => {
            callback(data);
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Let me break down this code a bit:

The PubSub class has a static events property, which is an object that will store all the events (or topics) and their corresponding subscribers (callback functions).

The subscribe method is used to register a new subscriber for a given event. It takes an event name and a callback function as arguments. If the event does not exist yet, it initializes it as an empty array in the events object. Then, it adds the callback function into the array of callbacks for the given event.

The publish method is used to publish new data to an event. It takes an event name and the data to be published as arguments. If the event does not exist or there are no subscribers for this event, it simply returns and does nothing. If there are subscribers, it calls each subscriber's callback function, passing the published data as an argument.

In the context of a chat application, the subscribe method would be used to register a new chat window that should receive new messages, and the publish method would be used to send a new message to all chat windows that have subscribed to receive new messages.

You can read more about how to use the publish and subscribe method across devices with the article: Understanding and implementing Event-Driven Communication in Front-End Development.

Real-time Data Engine

This is an important part of the architectural of a software development, and yet, in the majority of cases, not the business core of what you are building. Creating a reliable and scalable PubSub system that syncs data between different instances of our application can be challenging.

We are in 2024, meaning that there is already a solution to it: the Real-time Data Engine tools, specifically the SuperViz SDK. It offers a real-time collaboration and communication SDK and API, designed for developers building real-time web applications.

Using SuperViz you can create a room with several participants that when publishing an event it will be broadcasted to all the participants in the room that are accessing it through different devices and networks. This means that any updates made by one participant will be reflected in real time across all devices, providing a seamless and collaborative experience.

SuperViz provides the infrastructure necessary to build real-time, collaborative applications. This includes the ability to also catch this events on your backend using webhooks, and as well to publish an event with a simple HTTP Request, to name a few features.

Please let me know in the comments what other design patterns you would like to learn about, and don’t forget to share your knowledge!

Top comments (6)

Collapse
 
miketalbot profile image
Mike Talbot ⭐

Publish / Subscribe is a great pattern for micro front ends too. By using Pub/Sub you can create declarative systems where components created later can "opt-in" to framework areas and provide additional UI/ functionality etc.

Collapse
 
matatbread profile image
Matt

Hi! I found this and the previous article interesting, but you should also look at async iterators as they provide similar capabilities.

I wrote about my async iterators UI library here, but whether it's that or another framework, async iterators have numerous advantages such as

  • genuinely async operation
  • excellent native JS language support via async function * and for await
  • pull rather than push semantics, making lazy initialisation the default behaviour
  • both generator and consumer can terminate communication making the avoidance of leaks much easier

They are much better supported and more robust that homebrew Observers or lists of callbacks in a pub-sub context that are very easy to accidentally create memory leaks.

But I'd encourage anyone to investigate these kinds of loosely coupled, message passing UIs over a virtual DOM for performance & simplicity alone!

Collapse
 
enoch91 profile image
Info Comment hidden by post author - thread only accessible via permalink
Enoch Osarenren

Hello everyone, I hope you're all doing well. I recently launched an open-source project called GraphQLPlaceholder, and I'd love your support. Please check it out and give it a star on GitHub github.com/enochval/graphql-placeh.... Your support would mean a lot to me and help immensely in the project's growth.

Thank you.

Collapse
 
joset98 profile image
joset98

Thanks dude I like so much this simple explanation

Collapse
 
coder_dragon profile image
Shivam

PubSub is very useful design pattern, almost all real time multiple player games use this design for realtime online communication.

Some comments have been hidden by the post's author - find out more