Before I get into why I prefer the event hub, at least for my own application, I’d like to go over each of the methodologies a little so you can understand them better, just in case you haven’t heard much about them.
These have become all the rage these days, and for good reason. Rather than creating a function that allows you to send in a callback that is run when an action finishes, the function returns a promise object. Upon this promise object you can now call something like
done and send a callback into it that runs when/if the promise reaches a “done” state. A promise is created by a Deferred object. First you create a Deferred object and then return
deferred.promise(), which gives you your promise object. The deferred is used to update the status of the asynchronous action. For example, when the action is completed you would call
deferred.resolve(). When this is called, the promise will run all of the callbacks that were registered to it through the
Let’s look at some examples to compare traditional callbacks to using promises. These are taken from the Parse Blog because they do a pretty decent job of demonstrating the usefulness of using promises:
As you can see, in either case you end up nesting deeper and deeper with each action you perform. Here’s what it would look like if all three of the methods used in the above example returned promises.
As you can see, no matter how many actions we perform, the indentation only goes one level deep. The way it is written, it reads quite easily: “login, then find, then save, then… whatever we do when it’s saved.”
To do the chaining as it is done above, we need to use
then returns a new promise that is resolved either when the callback function returns a non-promise or the promise that the callback function returns is resolved.
For more on promises, you should check out the Q library and its documentation. jQuery also has a promises implementation, but as noted in an article by Domenic Denicola, it’s broken a bit. I still tend to use jQuery’s implementation because I don’t need an additional library and thus far it suits my needs.
I’ve already talked about using Event-Based Architectures, but I’ll still touch on it a bit more here. Rather, I’m going to give more concrete examples here. Using the event-based architecture is similar to the traditional callback way of doing things, except that you register the callback beforehand and it persists for use when an event is triggered again later. We’re going to use Backbone’s event system because it is similar to what I’m trying to use in my application. If you’re not familiar with Backbone, I suggest going through my screencast series on Backbone, but beware that newer versions of Backbone make this somewhat obsolete. Don’t worry, I’ll put together something to show you all the changes after 1.0 is released.
The example below is part of an application that starts and stops servers that run on the back end. The client app makes calls to the back end to start a server.
There’s a lot more to this example even though it essentially only does one thing. One thing I didn’t mention in the code is how the view’s
startServer method is called. We’ll assume it’s done via user interaction, such as clicking a “start server” button.
As you can see, in the
initialize functions of each of the above ‘classes’, we register our event handlers. This only happens once, so even if we start (and stop – even though I didn’t show code for stopping) a server multiple times, the handlers already exist and are ready to handle any event.
Do you see the awesome differences that events made?
startfunctions on the view and model are very small and only do one thing: start the server (according to their respective abstractions).
- The whole system is now able to know about the server starting. Nothing needs to have knowledge of any of the individual server models, but can still react when one of them starts.
The code examples for the promises pretty much showed some procedural programming. This is all well and good, but what about object-oriented programming? Objects’ methods need to be succinct, and if a single method is handling everything that is shown in that example, it may be a good idea to refactor.
I also like the event-based architecture better in this instance because in my real application I’m using WebSockets to tell the back end to start the server. WebSockets are already event-based, so it seems to make sense to use events for handling these sorts of things.
Finally, in this example, we have several layers of abstraction (plus one more in my real application), so for the most part, I’m just passing the promise all the way back and no one is using it until it gets to the view, in which case the promise would be used to do more than start the server, so it shouldn’t be in the
In all fairness, you can send a callback function with WebSockets (at least with Socket.IO; I’m not sure about WebSockets themselves) and use the callback function to resolve the promise as well as alert the rest of the system. In other words, you can use a combination of promises and events, but this makes it difficult to decide which is a better practice in each individual situation. However, as my application grows, I may end up needing to do just that. Time will tell.
The reason I wrote this article is because I recently spent much time arguing with myself on this very issue. How should the asynchronous actions be implemented in my application? I thought about it a lot, and even as I wrote this, I thought about it even more. They’re both great techniques and deserve to be looked at. In the end, this article is more to get you thinking about your asynchronous design decisions than it is to argue for one methodology over the other. God bless and happy coding!