简体   繁体   中英

Detecting When a Loop of AJAX Calls is Done

I have a web page that can submit an unlimited number of items back to the server for processing.

I've decided to submit these items in groups of 25 using AJAX calls to a web service. So my loop looks something like this:

// Submit elements
for (var i = 0; i < ids.length; i += 25) {

    var productIds = ids.slice(i, Math.min(i + 25, ids.length - 1));

    $.post('/Services/ImportProducts.asmx/ImportProducts', JSON.stringify({ importProductIds: productIds }))
    .done(function (result, statusText, jqxhr) {

        // TODO: Update progress

    })
    .always(function () {
        // TODO: Test for error handling here
    });
}

So far, this seems right. However, when all processing is complete, I want to refresh the page. And given the code above, I'm not seeing an easy way to perform a task when the last AJAX call has completed.

Since $.post() is asynchronous, this loop will complete before the AJAX calls have. And since the AJAX calls could complete in a different order than they were submitted, I can't simply test for when my last-submitted call is done.

How do I know when this code is done?

You can do this utilizing jQuery's promises . The general workflow involves you adding each of your promises to an array, then applying that array using jQuery when to execute another callback when all of the promises have returned.

Something like this should work:

var promises = []
for (var i = 0; i < ids.length; i += 25) {

    var productIds = ids.slice(i, Math.min(i + 25, ids.length - 1));

    var promise = $.post('/Services/ImportProducts.asmx/ImportProducts', JSON.stringify({ importProductIds: productIds }))
    .done(function (result, statusText, jqxhr) {

        // TODO: Update progress

    })
    .always(function () {
        // TODO: Test for error handling here
    });

    promises.push(promise);
}

/*
    Note, the "apply" function allows one to unwrap an array to parameters for a
    function call. If you look at the jQuery.when signature, it expects to be 
    called like: $.when(promise1, promise2, promise3). Using .apply allows you 
    to satisfy the signature while using an array of objects instead.

    See MDN for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
*/
$.when.apply($, promises)
    .done(function() {
        console.log("All done!") // do other stuff
    }).fail(function() {
        // something went wrong here, handle it
    });

You'd do that by pushing all the promises in an array, and using $.when to determine when they are all done

var ajaxArr = [];

for (var i = 0; i < ids.length; i += 25) {

    var productIds = {
        importProductIds : ids.slice(i, Math.min(i + 25, ids.length - 1))
    }

    ajaxArr.push(
        $.post('/Services/ImportProducts.asmx/ImportProducts', productIds, function(result, statusText, jqxhr) {
            // TODO: Update progress
        })
    );
}


$.when.apply(undefined, ajaxArr).done(function() {

    window.location.href = 'something'

});

You could set a count that is equal to the number of loops that you have to process and then on returning from the ajax request, decrement the counter and check for it being zero. When it reaches zero you can refresh the page

var remains = ids.length;

// Submit elements
for (var i = 0; i < ids.length; i += 25) {

    var productIds = ids.slice(i, Math.min(i + 25, ids.length - 1));

    $.post('/Services/ImportProducts.asmx/ImportProducts', JSON.stringify({ importProductIds: productIds }))
    .done(function (result, statusText, jqxhr) {

        // TODO: Update progress

    })
    .always(function () {

       // TODO: Test for error handling here

       remains--;
       if ( remains===0 ) {

             // TODO: refresh here
       }
    });
}

Just count how many callbacks are done; while callbacks are asynchronous, the code is run in a single thread, so they will be called sequentially, and you would be safe to assume that when count == 25 you're done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM