Darcy ClarkeDevelopment / Design / UX

Toggle Main Navigation

Nov 1, 2010

Library Agnostic Pub/Sub (Publish / Subscribe)

Posted in "development"


Update: Since writing this post I've started using a modified version of Peter Higgens jQuery specific pub/sub solution. Here's the updated version I'm using now, along with an App namespace:

App = {};
App.cache = {};
App.publish = function(topic, args){
    App.cache[topic] && $.each(App.cache[topic], function(){
        this.apply($, args || []);
    });
};
App.subscribe = function(topic, callback){
    if(!App.cache[topic]){
        App.cache[topic] = [];
    }
    App.cache[topic].push(callback);
    return [topic, callback];
};
App.unsubscribe = function(handle){
    var t = handle[0];
    App.cache[t] && $.each(App.cache[t], function(idx){
        if(this == handle[1]){
            App.cache[t].splice(idx, 1);
        }
    });
};
`</pre>

## <span style="font-weight: normal; font-size: 13px;">Over the past month or so the idea of Javascript Pubsub (Publish / Subscribe) has gotten a lot of publicity. [Rebecca Murphey](http://www.rebeccamurphey.com/) (of the [YayQuery](http://yayquery.com/) podcast / awesome JS dev) spoke at the jQuery Conference in Boston about it and more then a few example scripts have popped up for all sorts of different JS libraries (Dojo, jQuery etc.). If you don't know what Pub/Sub is you should definitely check out Rebecca's blog [post](http://blog.rebeccamurphey.com/pubsub-screencast) and Ben Nadal's [post](http://www.bennadel.com/blog/2037-Simple-Publication-And-Subscription-Functionality-Pub-Sub-With-jQuery.htm ) for more in depth detail.</span>

6 months ago I started, what I was calling at the time, jHooks (Javascript Hooks). The code I built around the idea of "hooks" was, in practice, the exact same thing as Pub/Sub. I've ported the code to use the, [Paul Irish](http://paulirish.com/) endorsed, Pub/Sub naming conventions. Having to change the code's object name was a struggle though. With "jHooks" it was very simple and straightforward to use that name as the object name and house all the methods subscriptions within it. I've reluctantly used the name "ps" until I find something better.

As the title of this post mentions, this version of pub/sub is library agnostic (and only 27 lines, un-compressed).

## The Code

Download: [http://darcyclarke.me/dev/pubsub/pubsub.js](http://darcyclarke.me/dev/pubsub/pubsub.js)
<pre class="brush:js">`    (function(window){
        ps = {},
        ps = window.ps,
        ps.subscriptions = [],
        ps.subscribe = function(name, callback){
            ps.subscriptions.push({"name": name, "callback": callback});
            return [name,callback];
        },
        ps.unsubscribe = function(args){
            for(x=0;x<ps.subscriptions.length;x++){
                if(ps.subscriptions[x].name == args[0], ps.subscriptions[x].callback == args[1])
                    ps.subscriptions.splice(x, 1);
            }
        },
        ps.publish = function(name, args){
            var temp = [];
            if(ps.subscriptions.length > 0){
                for(var x=0;x<ps.subscriptions.length;x++) {
                    if(ps.subscriptions[x].name == name)
                        temp.push({"fn":ps.subscriptions[x].callback});
                }
                for(x=0;x<temp.length;x++){
                    temp[x].fn.apply(this,[args]);
                }
            }
        };
    })(window);`</pre>

## Example Use

Set up a publish point with a string name and optional data to pass to the subscribed callback functions.
<pre class="brush:js">`$("submit").bind("click", function(){
    ps.publish("login", {"username":$("#username").val(), "password":$("#password").val() });
});`</pre>
Subscribe to a publish point using the same string as the identifier.
<pre class="brush:js">`ps.subscribe("login", function(data){
    console.log("Login Info: " + data)
});`</pre>
Unsubscribe by passing in the subscription
<pre class="brush:js">`var login_function = ps.subscribe("login", function(data){
    console.log("Login Info: " + data)
});

$(".clear_login_subscription").bind("click", function(){
    ps.unsubscribe(login_function);
});