jQuery Deferred object

15 במאי 2012

no comments

Suppose you need to fetch some data from your server by executing 3 different $.ajax requests.

Each request brings a different part of the total data. You don't mind in which order the requests complete.

Only when the 3 requests are completed successfully you can use the data. In addition, in case one of the method fails you need to execute some error handling code.

The naive solution looks something like that:

function getAllData(success, error, complete) {
    var count = 0;
    var errorInvoked = false;
    var successInvoked = false;
    var completeInvoked = false;
 
    var successHandler = function () {
        if (++count == 3) {
            success();
 
            successInvoked = true;
        }
    }
 
    var errorHandler = function () {
        if (!errorInvoked) {
            error();
 
            errorInvoked = true;
        }
    }
 
    var completeHandler = function () {
        if ((successInvoked || errorInvoked) && !completeInvoked) {
            complete();
 
            completeInvoked = true;
        }
    }
 
    $.ajax({
        url: "/GetData1",
        type: "GET",
        dataType: "json",
        success: successHandler,
        error: errorHandler,
        complete: completeHandler
    });
 
    $.ajax({
        url: "/GetData2",
        type: "GET",
        dataType: "json",
        success: successHandler,
        error: errorHandler,
        complete: completeHandler
    });
 
    $.ajax({
        url: "/GetData3",
        type: "GET",
        dataType: "json",
        success: successHandler,
        error: errorHandler,
        complete: completeHandler
    });
}

We are subscribing to the success/error/complete event of each ajax request and when all complete or one fails we execure the appropriate handlers

As you can see the code is not so elegant.

A better solution is to use jQuery Deferred object support. The secret is to use the return value of the $.ajax method which is a deferred object.

A deferred object is one that allows you to subscribe to its completion using a well known API.

For example, the oridinary $.ajax request:

    $.ajax({
        url: "/GetData1",
        type: "GET",
        dataType: "json",
        success: successHandler,
        error: errorHandler,
        complete: alwaysHandler
    });

Can be written using the deferred mechanism:

    $.ajax({
            url: "/GetData1",
            type: "GET",
            dataType: "json" 
        })
        .done(successHandler)
        .fail(errorHandler)
        .always(alwaysHandler);

So, how this mechanis can helpts us solving the original problem? 

$.when method knows to aggregate multiple deferred object into single one. Only if all deferred objects succeed then the aggregate one succeed too. If at least one of the deferred object fails the aggregate one fails too.

So our better solution is:

function getAllData(success, error, complete) {
    var getData1 = $.ajax({
        url: "/GetData1",
        type: "GET",
        dataType: "json"
    });
 
    var getData2 = $.ajax({
        url: "/GetData2",
        type: "GET",
        dataType: "json"
    });
 
    var getData3 = $.ajax({
        url: "/GetData3",
        type: "GET",
        dataType: "json"
    });
 
    $.when(getData1, getData2, getData3)
        .done(success)
        .fail(error)
        .always(complete);
}

See, the code is much simpler and easy to understand. Enjoy, …

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*