PubSub Design Pattern

Posted on in javascript, webdev

Welcome to this humble article on the PubSub design pattern in Javascript. If you have ever written a relatively big Javascript app you’ll know that it can get out of hand pretty quickly, for that very reason there are lots of solutions out there that you can use to aid you in this issue, design patterns are one of the most generic solutions and very often serve as a base for another more abstract solution, like an MV* framework such as Angular and Backbone.

A design pattern is simply a general reusable solution to a common problem, as you might expect the implementation is up to you, nevertheless a lot of production-ready implementations can be found out there, as we’ll discuss later on this article.

The good thing about design patterns is that they are robust and generally accepted solutions, so you are in good hands if you decide to use a certain pattern. It’s important to remember though, that when you have a hammer everything looks like a nail, you must know when to use it and when not to; in order to do this you need to clearly understand the advantages and disadvantages of the pattern you plan to use.

The PubSub design pattern stands for Publish/Subscribe, and might also be called Observer pattern. This is one of the most popular design patterns in modern Javascript, and for a good reason! The general idea of this pattern is to promote loose coupling, instead of objects calling other object’s methods directly, they subscribe to an event and they get notified whenever that event occurs.

Let’s get our feet wet with some code, as this is all quite abstract! A nice thing about PubSub is that it’s not a complex design pattern at all, in fact, the idea is pretty simple as we just want to be notified when something happens, so if we had a pubsub implementation, our code would look something like this:

As you can see the pubsub object exposes two methods, subscribe and publish, when we want to know whenever an event occurs we subscribe to that event, later on we can publish that event whenever in our code.

The pattern also exposes an unsubscribe method which simply removes a listener for a given event name.

Advantages of the PubSub Pattern

One of the most relevant advantages of this pattern is that it allows us to easily decouple our code, which inherently makes it more maintainable and easier to test. Another advantage is that it helps us to think in term of relationships between the different parts of our app, identifying which layers need to listen and which need to publish events.

We are also able to easily create dynamic relationships between the different entities of our app, making it quite flexible, as Addy Osmani says in his Javascript Design Patterns book:

Whilst it may not always be the best solution to every problem, it remains one of the best tools for designing decoupled systems and should be considered an important tool in any JavaScript developer’s utility belt.

Disadvantages of the PubSub Pattern

The main disadvantage of this pattern is that as we highly decouple the different parts of our app, it can get hard to guarantee that a part of our app is working correctly.
Also, as the dependencies are dynamic they can get hard to track.

Implementing the PubSub Pattern

Now that you have an idea of the pattern, let’s implement it! This is actually quite easy, one simplistic implementation could be as follows:

We can use this implementation as follows:

That would produce a message in the developer console Hello Federico!, as you can see it’s pretty easy to implement and use.

Other PubSub Implementations

There are a bunch of PubSub implementations, the one I like the most is Ben Alman’s Gist, which is really solid and succinct. Other alternatives include AmplifyJS and PubSubJS.

Using PubSub with AJAX

A very popular use for PubSub is whenever we are working with AJAX and async code, in the following example I illustrate a case where an user wants to search for posts, whenever the user clicks the #btn-search button our app should:

  • Send an AJAX request to fetch posts which correspond to a keyword
  • Update the search history with the new keyword

We could just do everything in one function, but let’s keep everything organized and decouple each task we need to perform:

As you can see we don’t need to wait for the AJAX request to finish to draw the search history, we can do it as soon as the button is clicked, on the other hand we do have to wait in order to draw the results. This somehow complex behaviour is easily and clearly implemented using the PubSub pattern. This scenario is pretty common in MV* frameworks such as Backbone which are getting increasingly popular, PubSub allows Backbone to easily decouple it’s different layers/actors from each other.

A Real World Example

Not too long ago I faced this issue and I was glad how easily PubSub solved it. Consider you are working in a quite big WordPress plugin which is divided into modules, each module must be independant of each other, meaning it’s possible to swap those modules anytime and their tests must not have any hard dependency, to archieve this this modules must able to “talk” to each other indirectly. How can we do this? Well we know that PubSub excels at decoupling so let’s try it out!

Out of all our modules, we are interested in two: favs and images. They both have a JS file: favs.js and images.js respectively.

We are given the task to implement “adding an image to favorites”; favs.js is in charge of favs, so without using pubsub a very bare-bones implementation of images.js might look similar to this:

There are some issues with that code, one is that we have to make some kind of global variable to be able to use the favs API from favs.js, we also assume that the favs.js file will be loaded before images.js; this isn’t a very big deal as we could fix it by using something like requirejs but still, what if we want to test that code? Testing the addToFavs function would depend on the window.favs object.

Using PubSub we can rewrite our code as follows:

Where did window.favs go? We don’t need it anymore! We just publish a favs/add event (note that it is a good practice to namespace your event names), the favs.js file will be listening and will react accordingly, triggering the favs/added and favs/failed events as needed. We have decoupled our little module, as a result we no longer need to use a global variable, have more flexibility on the loading order of the scripts, and more importantly we can now easily test our code by simply publishing events as needed; as a bonus this allows our tests to be more behaviour-driven rather than feature-driven, which is also a good practice :)

Promises: Another solution for async code

Promises are another tool we can use to deal with async code, they are gaining popularity and for a good reason! They can be quite helpful so it’s important to know what they are and when they should be used, they also plays nice with the PubSub design pattern.

The Mozilla Developer Network defines promises as follows:

The Promise interface represents a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers to an asynchronous action’s eventual success or failure. This lets asynchronous methods return values like synchronous methods: instead of the final value, the asynchronous method returns a promise of having a value at some point in the future.
A pending promise can become either fulfilled with a value, or rejected with a reason. When either of these happens, the associated handlers queued up by a promise’s then method are called.

That definition might be a bit hard to swallow, but it’s in fact pretty simple. Promises represent an entity which still doesn’t have a value, but it’s guaranteed that it will eventually either have a value (succeed) or fail.

A Promise must have a then function which accepts 3 callbacks, the first two are for success and failure respectively, the third one is to notify the consumer on progress, useful for very long operations but seldom used.

Something nice about promises is that they are chainable.

This code will print First callback and then Second callback. Something important to not is that if one callback fails, the following won’t get executed.

This allows us to execute async code in a synchronous manner, as we are used to. Also, if one of your callbacks returns a promise, the subsequent then call will be evaluated on that promise you returned, this makes chaining Promises easy as pie.

Common Promise Scenario #1

So by now you’ve read quite a lot on abstract promises, let’s get down to a real use case! I’ll illustrate two, the first one is for caching AJAX requests. First let’s write an implementation without promises:

The code above simply loads a song by id only once and then executes a callback. Not too bad, a lot of Javascript code looks like that, but we can do better! Let’s use Promises! Because Promises only get resolved once, if then is called when a Promise is already resolved, the callback will be executed immediatly, because of this and also taking advantage of jQuery’s promises implementation we can easily cache AJAX requests as jQuery AJAX functions actually return promises:

Much better! You might notice the use of .promise(), this is because jQuery uses Deferred, which is a superset of Promise. In this case we just want to return a Promise object which can be resolved only once, so we use .promise(). The code would also work if we returned a Deferred but it’s a good jQuery practice to always return Promises.

Note on jQuery’s Promises: There is a catch with jQuery Promises, they aren’t fully compatible with the Promises specification as you can see in Domenic Denicola’s article so there are some edge cases, but I find it convenient to use jQuery’s implementation to demonstrate the concept as it’s used by a wide variety of developers. If you want a more loyal implementation you can try other libraries such as Q, rsvp or when.js as Domenic suggests.

Common Promise Scenario #2

This situation it’s also quite common, it happens whenever we have to wait for several async actions to finish before proceeding, for example:

Now that’s ugly, callback spaghetti should always be avoided! Luckly a lot of libraries which implement Promises also provide method called when which resolves when all it’s arguments (which are promises) are resolved, knowing this we can simply code:

That’s much better, now the first two AJAX requests are executed at the same time, so it will be considerably faster. Moreover, the code is much cleaner, but we can still improve! Remember that we can chain then calls? Let’s try that:

Looking good! Promises are awesome, don’t be afraid to use them and try them out. If you want to know more about Promises I highly reccommend watching this great jQuery conference talk by Alex McPherson. I also wrote a brief article on the subject.

Conclusion

PubSub as well as all design patterns has known advantages and disadvantages which you should know very well. It’s main strength is highly decoupling the different parts of your application, but it also helps us work with async code and is pretty easy to use and get started, so don’t hesitate to try it out in your next project!

Promises can be used in conjunction with the PubSub pattern and are a very important tool we can use to deal with complex async events, as well as avoiding callback hell.

References

The following are references I used for writing this article and are recommended reads on the subject.

  • skrat

    Now that you juxtaposed pubsub and promises, perhaps CSP would be a good fit to improve on your article. Thanks

    • gosukiwi

      Thanks for the suggestion! I’ll have it in mind for a follow up article :)

  • Capaj

    I hate it when people abuse pubsub in Angular. I prefer to write Angular apps without using pubsub at all and it is exactly like you mentioned-for complex scenarios, it is much easier to track what is happening when instead of listening to an event, I have a watcher which reacts to the data change in some service.

  • Joshua C

    I know this post is old but it’s very helpful so I would like to point out a code correction. In the pubsub section the “unsubscribe” function has an error.

    unsubscribe: function (evt, callback) {
    var idx = subs[evt].indexOf(callback);
    subs.splice(idx, 1); // < —– error
    }

    should be:

    unsubscribe: function (evt, callback) {
    var idx = subs[evt].indexOf(callback);
    subs[evt].splice(idx, 1); // <—– subs[evt] added
    }

    Thanks for the article!

  • Frederic Rufin

    Pub/sub is a great pattern, but we often have to create publishers/listeners in opposite directions as we may expect replies.
    Starting from another implementation, i added bidirectionalilty with silent, temporary reverse pub/sub, to avoid useless hard-coding :
    https://github.com/frufin/js-bidirectional-pubsub

    Opinions are welcome !