This is a summary of my presentation today at the sf javascript meetup #4 on maintainable front end architecture in javascript. The presentation involves a demo app and a progressive construction of the model’s subscribe method, which contains the meat of the functionality and interesting javascript.
Demo app:

Decoupling Data and UI in webapps with PubSub patterns
As web applications become more powerful, they grow in complexity. Front end programming patterns and best practices are becoming more and more important both for the community and for the industry.
If you decouple your application’s data and UI layers, you will be able to easily extend and develop one layer without affecting the other. A powerful pattern that allows for such decoupling is publication/subscription.
It turns out that javascript’s combination of functional programming and the ability to apply a scope at runtime makes it a wonderful language to write a PubSub library in. 25 lines of code is enough to create a highly versitile model with both dynamic scoping and currying/partial application. We’ll go through that code together in a moment.
If you look at the application code (not more than some 70 lines), then you notice that the UI and the data layers are completely independent - i.e. they don’t reference each other. All the message passing between the data and the UI are taken care of with code like this:
pubSubBroker.subscribe('email-open', gData, 'onRead');
pubSubBroker.subscribe('email-open', gUI, 'markEmail', true);
var email = {title:'Test email', id:1, body:'Test body'};
//This will call both gData.onRead(email) and gUI.markEmail(true, email);
pubSubBroker.publish('email-arrive', email);
The pubSubBroker creation and publish are both pretty straight forward:
// Our publication and subscription broker
function PubSubBroker() {
var signals = arguments;
this.subscribers = {};
for (var i=0; i < signals.length; i++) {
this.subscribers[signals[i]] = [];
}
}
PubSubBroker.prototype.publish = function(signal) {
var args = Array.prototype.slice.call(arguments, 1)
for (var i=0; i < this.subscribers[signal].length; i++) {
var handler = this.subscribers[signal][i];
handler.apply(this, args);
}
}
However, the subscribe method is the fun part. Let’s go through its creation step by step in order to understand how we get to the final, slightly non-trivial 7-line implementation. First, we just want the ability to subscribe to signals with a function handler:
PubSubBroker.prototype.subscribe = function(signal, handler){
this.subscribers[signal].push(handler);
}
Then we add the ability of specifying the scope in which the handler will run on when a signal is published. Use handlerName rather than handler directly, and use call to run the handler in the given scope.
PubSubBroker.prototype.subscribe = function(signal, scope, handlerName){
this.subscribers[signal].push(function(eventArguments){
scope[handlerName].call((scope || window), eventArguments);
});
}
The third version adds the ability to pass in a variable number of arguments to publish. Using apply rather than call allows for this.
PubSubBroker.prototype.subscribe = function(signal, scope, handlerName){
this.subscribers[signal].push(function(){
scope[handlerName].apply((scope || window), arguments);
});
}
Finally, we make currying possible, which allows for partial application that can be super useful in many cases (let me know if you want a useful example and I’ll add it):
PubSubBroker.prototype.subscribe = function(signal, scope, handlerName){
var curryArray = Array.prototype.slice.call(arguments, 3);
this.subscribers[signal].push(function(){
var normalizedArgs = Array.prototype.slice.call(arguments, 0);
scope[handlerName].apply((scope || window), curryArray.concat(normalizedArgs));
});
}
That’s it! If you want to play with the code, just download the zipfile with the demo application and pubsub code or check out the demo - it has links to the application file, pubsub broker file, as well as the progressive build of subscribe.