Providing Synchronous / Asynchronous Flexibility With jQuery.when

I’ve quickly become a fan of jQuery’s Deferred / Promise features. They’ve been around for a little bit now, but I only recent started using them and they’ve helped me solve a number of problems with my asynchronous JavaScript code. But what I recently figured out really blew my mind. You can use jQuery to support both synchronous and asynchronous code, with the `$.when` function, and your code doesn’t have to care whether or not it’s async.

$.when(something).then(doSomething);

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:

 var that = this;

 var templateRetrieved = this.getTemplate();

 $.when(templateRetrieved).then(function(template){
   var html = that.renderTemplate(template, data);
   that.$el.html(html);
 });

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.

$.when.then: Async

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.

$.when.then: Synchronous

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.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Async, Backbone, Javascript, JQuery, Marionette. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Dave Cadwallader

    Gotta love patterns that let you work smarter, not harder.  Thanks for the great write-up!

  • http://twitter.com/th3mus1cman Tom Brewer

    Another jQuery gem that is often overlooked is the jQuery.proxy method: https://gist.github.com/2216288 Great article by the way. I was not aware of jQuery.when.

    • http://mutedsolutions.com Derick Bailey

      Oh nice. I didn’t know jQuery had a proxy method for that. Most of the time, I have Underscore.js in my apps, so I tend to use _.bind and _.bindAll. Looks like they do the same thing, though. Good to know.

  • http://twitter.com/Gareth_Elms Gareth Elms

    Thanks for bringing this under my radar I read all your posts here.

    I had to write something fairly similar and for what it’s worth here it is 
    http://jsfiddle.net/bqC6U/3/My single page app makes an ajax call immediately after a page refresh to load the data. I have routed js modules that are dependent on this data waiting to render the backbone views. I didn’t want to trigger an event like “dataLoaded” in case the event was subscribed to after it had already fired. Any feedback (negative I assume) on my jsfiddle would be appreciated. I expect this problem has been solved before much more elegantly many years ago but my code is at least robust. Or is it?

  • http://twitter.com/kmurph79 Kyle_Murphy

    Holy crap, thanks so much.  Am now using it for synchronizing multiple ajax calls.

  • http://www.facebook.com/joao.mamede João Mamede

    Derick, I can see the value and I’ve used this approach for async calls but for sync ones not sure if it really helps me rather than allowing the execution of multiple (chained or not) callbacks (e.g. with the done() method).

    Am I right? Thanks for another great post! 

    • http://mutedsolutions.com Derick Bailey

      the real value of using $.when is not caring if it’s a sync or async call, as i tried to show in this post. 

      if your function returns a promise, you can do this:

      var foo = doSomething();
      foo.done(function(){
        // it’s done
      });

      but if, for some reason, the doSomething function changes so that it no longer returns a promise, but now returns a plain javascript object or a string or something, this code will break because there won’t be a “done” method on the returned object.

      by using $.when(foo).then(function(){…}) instead, we don’t care what the return type is. it can be a promise, in which case the callback will fire when the promise resolves. or, it can be a plain old object or a string or anything else, in which case the callback will fire immediately.

    • http://twitter.com/PostHopeLive Paul Barton

      Good example of this usage is caching Ajax calls :

      (function($, exports) {
          exports.cache = {};
          exports.getAjaxData = function(url) {
              return cache[url] || $.get(url);
          };
      })(jQuery, window);

      $when(getAjaxData(‘foo.html’)).then(function(response) {
          //do something with data
      cache['foo.html'] = response;
      });