Decoupling JS apps using publisher subscriber pattern

http://dev.housetrip.com/2014/09/15/decoupling-javascript-apps-using-pub-sub-pattern/
https://gist.github.com/fatihacet/1290216

The problem

Let me use one of the most common features in modern web applications to introduce the problem: sending notification emails.

Let’s say we’re building an e-commerce site and we’d like to send a notification email to the customer when they make a purchase. A simple solution, and probably the most common one, could be something like this:

Notice how in sendEmail definition, it creates an instance of Mailer and calls function “sendPurchaseEmail”.
These two objects now have tight coupling because if you were to change sendPurchaseEmail to another name, you’ll have to do the same for sendEmail in Order. In other words, if you were to change the # of parameters, or the interface of the sendPurchaseEmail function, you’ll have to repeat those steps for sendEmail in Order.

Usually you know two components are coupled when a change to one requires a change in the other one, and that’s the case. If we want to change the name of the sendPurchaseEmail method or their params, we’ll have to change Order implementation as well. In a large application this bad practice means having a tightly coupled application where a small change can easily end up in a waterfall of changes.

What we want is Loose Coupling. Loose coupling is when you change the interface, but do not have to worry about changing it in all the other places that you have used it.

What is the Publish Subscribe Pattern?

In software architecture, publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers. Instead, published messages are characterized into classes, without knowledge of what, if any, subscribers there may be. Similarly, subscribers express interest in one or more classes, and only receive messages that are of interest, without knowledge of what, if any, publishers there are.

This pattern uses an event system that sits between the objects wishing to receive notifications (subscribers) and the objects firing the events (the publishers). This event system allows code to define application specific events which can pass arguments containing values needed by the subscriber. The goal is to avoid dependencies between the subscriber and the publisher.

Implementation

First, we declare a global literal object. This object takes will have the functionalities of publishing and subscribing.

It will be passed into an IIFE so that it has private block scope for its data structures.

then we create the data structures and variables needed for the implementation.

Say there’s a couple of topics: Badminton, Boxing, and Swimming.
First, we use the concept of key: value in order to keep track of them.
The key is the activity name “Badminton”, “Boxing”, “Swimming”.
We have a topics literal object that will store these keys.

TOPICS:

{
“Badminton” : [subscriber1, subscriber2, subscriber3….subscriber n]
“Boxing” : [{token: abcdefg, func : callback}… {token: 38fje8, func : callback}],
“Swimming” : [{token: a1b2c3d4, func : callback}… {token: 0fjdue7, func : callback}],

etc
}

Then for each key, we will have a literal object as the value.

That literal object has 2 properties:
– token
– func

token is simply an uid
func is the callback provided by the subscribers. Essentially, whenever something happens
and we want to publish something, we call this func, then pass in some data if needed.

“Badminton” : {token: a4456iol, func : callback}

Hence for each topic, we have an array of objects. Each of these objects have token and func properties. These objects represent
external objects that has subscribed to us and want to receive notifications when something happens.

Subscribe

Therefore, we create a public function property called subscribe. Its first parameter is topic, which is the topic that the external object
wants to subscribe to. For example, badminton, swimming…etc. The func, is the callback that we can use to notify that external object.

We must check to see if the topic exist. If there’s only data for say Badminton, and we subscribe to “swimming”, our pubsub system
will create an key/value entry for swimming and then create an empty array. This readies future external objects that wants to
subscribe to the topic “swimming”.

Then, we simply use a increment to simulate id generator. It is assigned to the subscriber. That way, each subscriber has an unique id to identify itself.

Finally, we create an object to store the token and the callback for the subscriber. We store this object into the array that corresponds to the topic that the subscriber wanted.

When we publish, we call execute this callback so that its owner will receive it.

Publish

So we have all these subscribers stored for different topics and now we’re ready to publish!

We create a public property for the pubsub. The first parameter topic represents the topic we want to publish for.
args is any published data you want to pass to the objects stored in arrays of different topics (subscribers).

First we check to see if there are any subscribers for the topic at hand. If say we have 3 subscribers for “Badminton”, and we try to publish something for “swimming”, we just spit out an error message because no such topic exist.

{
“Badminton” : [subscriber1, subscriber2, subscriber3]
}

Then we use a setTimeout to simulate internet activity.
First we get the array of subscribers by accessing the value by using topic as the index.

In an associative array, giving the topic key will give us the object value (array of subscribers).

Then we simply get the length of the subscribers.

By using the length, we use it to access the array of subscribers by using index. Remember, using strings in an associative array
will give you the object value associated with it.

By using numeric index, you’ll simply be giving the object value by index.

Hence after getting the length, we simply go through the subscriber array by looping through its index from length to 0, and
calling each subscriber’s callback. We can pass in whatever data we like for the publish.

Using the pubsub object

Unsubscribe

First, we go through all the topics available in our topics associative array.
For each of these topics, there is a list of subscribers.

For each element of the array subscribers, we check to see if the subscriber has the token.
If so, we remove that subscriber from the subscribers’ array.

FULL SOURCE