Jacob Orshalick is a software consultant, open source developer, and author. He is the owner of solutionsfit, a consulting firm dedicated to aligning businesses with technology. His software development experience spans the retail, financial, real estate, media, telecommunications, and health care industries. Jacob is a DZone MVB and is not an employee of DZone and has posted 13 posts at DZone. You can read more from them at their website. View Full User Profile

Cleanup Your jQuery by Deferring

10.06.2012
| 1599 views |
  • submit to reddit

The asynchronous nature of AJAX sometimes makes jQuery code a bit hard to follow. Embedding callbacks in AJAX calls starts off reasonable, but enough callbacks can quickly become unwieldy.

If your code base is suffering from this issue, have a look at the jQuery Deferred API. jQuery Deferred is an implementation of the CommonJS Promises Spec.

The CommonJS Promises Spec attempts to put an API around the consistent pattern of handling asynchronous callbacks. In the case of jQuery Deferred we are generally talking about AJAX calls. Let’s look at an example that will help to clarify the scenario.

Traditional Approach

Let’s say you have two services you are invoking to show information on a map. One service provides the latitudinal and longitudinal coordinates (geolocation) of an address, while another service provides nearby businesses.

function findGeolocation(address){
    $.ajax({
      url: "/echo/json/",
      data: {json: JSON.stringify({"address" : address})},
      type: "POST",
      success: function(geolocation) {
        findNearbyBusinesses(address, geolocation);
      }
  });
}

function findNearbyBusinesses(address, geolocation){
    $.ajax({
      url: "/echo/json/",
      data: {json: JSON.stringify({"address" : address})},
      type: "POST",
      success: function(businesses) {
        showLocationMap(geolocation, businesses);
      }
}

It’s difficult to follow the control structure of the above code due to the embedded callbacks. The $.when method from the jQuery Deferred API helps clean this up.

Using jQuery Deferred

Instead of embedding our control flow in the callback functions themselves, we can specify the flow through an API. The $.when method accepts a list of functions that return a Deferred object. The $.ajax API returns a Deferred object allowing us to directly pass the result of AJAX invocations to the $.when method.

Once an AJAX request completes, the Deferred object is considered “done”. The $.when method waits for all Deferred objects to reach the “done” state and then invokes any handler functions that have been specified for the following:

  • done – handlers always called once all Deferred objects complete
  • then – handlers called if all Deferred objects complete successfully
  • fail – handlers called if a failure occurs with one of the Deferred objects

Now let’s rewrite our above code snippet to use the $.when API.

function findGeolocation(address){
    return $.post(
        "http://solutionsfit.com/geolocate",
        {json: JSON.stringify({"address" : address})}
    );
}

function findNearbyBusinesses(address){
    return $.post(
        "http://solutionsfit.com/nearbyBusinesses",
        {json: JSON.stringify({"address" : address})}
    );
}

$.when(findGeolocation(address), findNearbyBusinesses(address))
    .then(function(geolocation, businesses) {
        showLocationMap(geolocation, businesses);
    });

Notice that the readability now clearly defines the control flow. This now reads as:

when we find the geolocation and any nearby businesses, then show the location and businesses on a map

In addition, in the second case we’ve improved performance by allowing our AJAX calls to execute simultaneously. In the first case, the retrieval of nearby businesses was forced to wait on the geolocation call due to the embedded callback.

There is much more to the API and you can review all the details here.

Published at DZone with permission of Jacob Orshalick, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)