I recently wrote a post about sprinkling various controller-esque functionality in Backbone Collections for acting as the event hub for the items within their respective collections. The one caveat to the example presented is the tight-coupling that the
Concept have to
AppState. While implementing this (in my real project), I became frustrated with needing to specify which objects needed to bind to other objects. The other issue with binding to specific objects and loading data asynchronously from the server is needing to include the event binding (or worse initialization) of objects within AJAX success callbacks of dependent objects. Again, tight-coupling.
- Publishers publish content
- Subscribers subscribe to content
But, wait?! That sounds a lot like binding (subscribing) and triggering (publishing) events?
Yes it is similar, but with one exception, subscribers and publishers are completely (and intentionally) unaware of each other. This is accomplished by having a central Hub that publishers can publish their content to and subscribers can subscribe to various content feeds. Let us modify the points:
- Publishers publish content to the Hub
- Subscribers subscribe to topics or feeds provided by the Hub
- The Hub pushes new content out to it's subscribers as it receives it from publishers
Having this central hub_ ensures loose-coupling between various objects that depend on or otherwise may respond to actions invoked by other objects._ This solves the first problem mentioned above, but what about managing asynchrony? One of the known disadvantages with a vanilla pub/sub architecture is it's requirement for subscribers to be online virtually all the time to receive incoming published content. Thus, if a subscriber does go offline, any content published during that time will be missed by the subscriber.
I wrote a bit more powerful implementation which supports queues and thus late subscribers. It also has support for undoing/redoing content pushes. As first glance, that may sound a bit weird and unnecessary (which to some extent I agree), but it flowed while writing it. I intend to break out the undo/redo API as a separate branch for those who do not need or are uninterested of that extra layer.