An Improved PubSub for jQuery

On my last screencast I talked a bit about PubSub and how you could apply it to jQuery. In that one I used “Cowboy” Ben Alman’s jQuery Tiny Pub/Sub.

That works great, but I wanted a little something more/different. First, it’s sorta using the DOM for PubSub, which feels weird (though it admittedly works quite well).  The rest of my issues stem from the fact than I’m an utter crap coder. If you run into a problem (read: bug) in a subscriber, it takes all of the subscribers down. For example, say you have 3 subscribers, and 1 of them has a bug. When you publish, you’re going to flame out at the bug, and some of your subscribers may never fire. That’s a drag, and I couldn’t figure out how to elegantly add some error trapping when using jQuery’s On/Off/Trigger other than sitting it in every subscriber. I also really wanted to be able to console.log() a list of subscribers for debugging purposes.

So, I took Peter Higgin’s great PubSub script which is cached array rather than DOM oriented and tweaked it a bit. I added a try/catch block in publish that keeps an error in one subscriber from blocking the others and I added a subscribers function to list all subscribers so I can keep my head on straight while coding. I also fiddled with unsubscribe so it takes a topic and callback rather than a handle so I can unsubscribe a bit easier (i.e. works the same as subscribe).

Here’s the final result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*    
    jQuery pub/sub plugin by Peter Higgins
    https://github.com/phiggins42/bloody-jquery-plugins/blob/master/pubsub.js

    Modified by Tobin Bradley

    AFL/BSD Licensed
*/
;(function(d){
    // the topic/subscription hash
    var cache = {};

    // Publish some data on a named topic.
    d.publish = function(/* String */topic, /* Array? */args){
        cache[topic] && d.each(cache[topic], function(){
            try {
                this.apply(d, args || []);
            } catch(err) {
                console.log(err);
            }
        });
    };

    // Register a callback on a named topic.
    d.subscribe = function(/* String */topic, /* Function */callback){
        if(!cache[topic]){
            cache[topic] = [];
        }
        cache[topic].push(callback);
        return [topic, callback]; // Array
    };

    // Disconnect a subscribed function for a topic.
    d.unsubscribe = function(/* String */topic, /* Function */callback){
        cache[topic] && d.each(cache[topic], function(idx){
            if(this == callback){
                cache[topic].splice(idx, 1);
            }
        });
    };

    // List Subscribers
    d.subscribers = function(/* String */topic) {
        l = [];
        cache[topic] && d.each(cache[topic], function(idx){
            l.push(this.name);
        });
        return l;
    };

})(jQuery);

And you would use it like this:

[crayon lang=“javascript”] $.subscribe(“/some/topic”, handle1); $.subscribe(“/some/topic”, handle2);

$.publish(“/some/topic”, [“a”,“b”,“c”]);

$.unsubscribe(“/some/topic”, handle1);

console.log(​$.subscribers(“/some/topic​​​​​​​​​​​​​​​​”));​​​​​​​​​

“`

It’s still very little code to get PubSub up and working with jQuery, but it adds some needed functionality for hacks like myself.