{ Publisher Subscriber Pattern }
A few weeks ago I was introduced to the Publisher Subscriber pattern in JS, pretty much confused by the methodology behind it I decided to give it a go.
The publisher subscriber pattern allows several methods to subscribe to a particular event. Methods and functions can unsubscribe and subscribe to any event at will, this is handy if you want to remove or add a method to an event handler at runtime.
For example, we would normally do something like this in jQuery
$('.button').click(function(i){
doFoo();
doBar();
});
This can get pretty messy especialy if we later decide to add new methods to the event handler. We can irradicate this by introducing publisher subscriber.
var buttonPublisher = new Publisher();
var fooFn = function(el){};
var barFn = function(el){};
buttonPublisher.subscribe(fooFn);
buttonPublisher.subscribe(barFn);
$('.button').click(function(i){
buttonPublisher.notify(this);
});
This in effect stops you from needing to add or remove functions within event handlers, and keeps them clean and tidy. One line of code replaces several. This isn’t the main benefit of the publisher subscriber pattern though, the beauty of this pattern becomes apparent when you need to unsubscribe a method based on the outcome of another event.
$('.removeFoo').click(function(i){
buttonPublisher.unsubscribe(fooFn);
});
Can you see where I’m coming from now? To achieve this without the publisher subscriber pattern you would need to set up a boolean and check to see whether you can perform an action, or create multiple click event handlers, which can get pretty nasty if you have quite a few things you need to do, it’s just as bad as writing onclick=”doFoo(); doBar(); doFoo1(); doBar1()” in your html.
I’ve done all of the hard work for you, this is a pretty basic publisher subscriber class.
/**
* @author gwilliams
*/
var Publisher = function(){
var _subscribers = [];
return {
/*
* Pushes the subscribers callback function into
* the private _subscribers property.
*/
subscribe: function(fn){
_subscribers.push(fn);
},
/*
* Method is used to unsubscribe a subscribers callback function
* from the publisher.
*/
unsubscribe: function(fn){
_newSubscribers = []; // Create an empty subscriber array
/*
* Loop through the _subscribers array, checking to see
* whether the function in 'fn' matches any function in
* the _subscribers array, if it doesn't match, push it
* in the _newSubscribers array.
*/
for (var i = 0; i < _subscribers.length; i++) {
if (_subscribers[i] !== fn) {
_newSubscribers.push(fn);
}
}
/*
* Now the _newSubscribers array only contains the callback
* methods we want we can re-assign it to the private
* _subscribers property.
*/
_subscribers = _newSubscribers;
},
/*
* Wipes the subscriber list
*/
wipe: function(){
_subscribers = [];
},
/*
* Returns all of the current subscribers in an array
*/
getSubscribers: function(){
return _subscribers;
}
/*
* The notify method is used to invoke all of the callback methods
* in the _subscribers array, o is the property to be sent to the
* subscriber method, this can be anything from a string to an object
* or even JSON.
*/
notify: function(o){
for (var i = 0; i < _subscribers.length; i++) {
_subscribers[i].call(o);
}
}
}
};
September 4, 2008 - 7:57 am
I really like this example, and it is something I will have to consider implementing in the future. I’m constantly having to do stuff like this for my clients, so any little bit to help me wrap my mind around it helps.