6

I have some (lets say 5) ajax requests that I run at the same time by using jQuery.ajax function.

Now I would like to synchronize and aggregate their results and I used jQuery.when function to achieve this.

My problem is that $.when returns as soon as one of the requests failed and prevent the others to return even if they succeed.

How can I sycnhronize and get all the results from all my ajax requests (those that failed and those that succeed) ?

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
Riana
  • 689
  • 6
  • 22

2 Answers2

0

You could define one, two or three update functions (depends on what you want to do) that take the response of the corresponding promises (ajax callbacks):

function bindPromises(updateSuccess, updateFail, updateAnyway) {
    var arrPromises = [];

    // automate the promise retrieval if you want, that's up to you.
    arrPromises[0] = ajaxRequest1();
    arrPromises[1] = ajaxRequest2();
    arrPromises[2] = ajaxRequest3();
    arrPromises[3] = ajaxRequest4();
    arrPromises[4] = ajaxRequest5();

    for(var j = 0; j < arrPromises.length; j++) {
        arrPromises[j].then( updateSuccess, updateFail, updateAnyway );
    }
}

Or if you want to automate even more:

function bindPromises(arrayOfAjaxCalls, updateSuccess, updateFail, updateAnyway) {
    var arrPromises = [];

    for(var i = 0; i < arrayOfAjaxCalls.length; i++) {
        arrPromises[i] = (arrayOfAjaxCalls[i])();
        arrPromises[i].then( updateSuccess, updateFail, updateAnyway );
    }
}

If you're not familiar with Promises I would like to point you to a great article covering that topic: Understanding jQuery.Deferred and Promise

nirazul
  • 3,928
  • 4
  • 26
  • 46
  • Hi, correct me if I'm wrong but it seems to me that your code executes each callback for each ajax response isn't it ? What I am lookig for is a solution where one method will be executed only once when all requests are finished (not matter if they all succeed or not). From this method I should be able to get all ajax call responses (those that failed and succeed). – Riana Nov 25 '12 at 17:44
  • No, you're right. But I wasn't sure wether you wanted to wait until all the calls are over or decide to take some action after every call is finished. Apparently you now have examples for both approaches ;) – nirazul Nov 25 '12 at 21:45
0

Working demo: http://jsbin.com/ocawoj/4/edit

function waitForAllPromisesToFinish () {
    var i,
        responses = [],
        deferred = $.Deferred(),
        helpers = {
            addToResponses: function (index, data) {
                responses[index] = data;

                var i = 0,
                    isAnyNull = false;

                for (i = 0; i < responses.length; i++) {
                    if (responses[i] === null) {
                        isAnyNull = true;
                        break;
                    } 
                }

                if (isAnyNull === false) {
                    deferred.resolve(responses);
                }
            },
            setupPromise: function (promise, index) {
                promise.always(function () {
                    var args = Array.prototype.slice.call(arguments);
                    helpers.addToResponses(index, args);
                });
            }
        },
        ajaxPromises = Array.prototype.slice.call(arguments);

    for (i = 0; i < ajaxPromises.length; i++) {
        responses[i] = null;
    }

    for (i = 0; i < ajaxPromises.length; i++) {
        helpers.setupPromise(ajaxPromises[i], i);
    }

    return deferred.promise();
}

The function returns a promise. You attach a done handler slightly different from the one you provide to $.when(). The function keeps track of the responses of each ajax promise. Whenever it finds that all ajax promises have returned data, either success or failure, it will resolve the promise.

There may be more efficient ways to achieve the same, though this is first that I thought of.

Amith George
  • 5,806
  • 2
  • 35
  • 53
  • Hi ! It seems this does exactly what I am looking for ! But to be honest I was secretly hoping for more "standard" way to do it as I thought I am not the first man on earth trying to resolve this kind of problem. Anyway , thank you for your respone and time ! :) – Riana Nov 25 '12 at 17:54
  • I just went through the code of `$.when` and what I have done is very similar to what `$.when` does. The difference is `$.when` calls `deferred.reject` the moment any of the deferreds fail. It does make sense because otherwise how do you know if any of the deferreds failed? You will need to check the resp of each deferred to figure out if its a success resp or a failure resp. You could raise this as a ticket on their bug tracker and maybe you might get some feedback on how the core team feels this should be addressed. – Amith George Nov 25 '12 at 18:18
  • I agree that it's not a bug, '$.when' works this way, it makes sense and it's ok. I think, it is just a lack of feature because there are many cases where we need a kind of 'whenAll' function which synchronizes all the results no matter if they succeed or not. I have to say that I'm quite surprised that there is no such function available out of the box or a workaround (the "standard" way as I called it before). – Riana Nov 26 '12 at 10:03