Providing Synchronous / Asynchronous Flexibility With jQuery.when
The core of the $.when syntax is the when/then statement. It’s a simple logical progression in syntax and I think it reads quite nicely: When this condition is met, then execute this code. Of course you can make the statement say things that don’t quite make so much sense if you name your variables oddly, but I prefer to name them so that they do create this type of flow.
For example, you’ll find code similar to this in my Backbone.Marionette project:
In this example, I’m waiting for a template to be retrieved before rendering my view. After the template has been retrieved, I’m using that template to do the rendering. The code reads fairly well, in my opinion: When the template has been retrieved, render the view.
If I’m using an asynchronous template loading mechanism for my Backbone.Marionette views (like in my BBCloneMail sample app), the above code only needs to have a jQuery deferred object returned from the call to “getTemplate” on the view. If a deferred / promise is returned, then the $.when/then call will be set up to execute the ‘then’ callback after the template has completed loading. It’s a fairly simple thing to do, honestly. Just return a deferred / promise from “getTemplate” and the view rendering will correctly support asynchronous template loading.
The real magic in this code, though, is that it supports both synchronous and asynchronous returns from the “getTemplate” method.
If you can sift through all of the documentation and really wrap your head around it, you’ll find this little nuget:
If a single argument is passed to jQuery.when and it is not a Deferred, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately.
What this is really saying is that if you call $.when with a deferred/promise, then jQuery will wait until that promise has been fulfilled – resolved – before executing the ‘then’ portion of your code. At the same time, if you pass in an object that is not a jQuery deferred/promise, jQuery will immediately call the “then” callback in your code. This means that a call to $.when/then directly supports both synchronous and asynchronous processing.
You can see this evidenced in Backbone.Marionette, once again. The default implementations of the template loading and rendering for the various views are all synchronous. I’ve added extensive support for asynchronous template loading and rendering, though, using a combination of Deferred objects and $.when/then calls. The above code sample runs no matter the sync/async nature of the template loading and rendering, though.