How do you use .when().then() to trigger a functio

2019-04-09 20:59发布

问题:

I have a page in which I have a variable number of AJAX calls to make which are triggered on a common event. The AJAX calls themselves are to update related fields in a SQL database. Once all the calls are complete, I want to refresh the page so that it now reflects the changes just made.

I used the following question/answer on here to get so far.. jQuery when each is completed, trigger function

Here is my code so far:

var team_update = function(e) {
    var $items = $('.sortable-items');
    var XHRs = [];

    $items.each(function(){
        var team_id = $( this ).attr("id");
        var data =  {
            tid: team_id,
            users: $('#' + team_id).sortable('toArray')
            };

        XHRs.push(
            $.ajax({ 
                type: "POST", 
                url: "update.php", 
                data: data, 
                complete: function(data){
                } 
            })  
        );

    });

    $.when(XHRs).then(function(){
        console.log('Refreshing Screen');
        $('#content-wrapper').load( 'index.php' );
    });

}

What I was expecting to happen, is that the $('#content-wrapper').load( 'index.php' ); would fire, once all my ajax() requests had completed. What appears to be happening though, is that the callback is firing once all the requests have been sent, not necessarily after they have completed, and so sometimes my page update still has 'old' data on it.

The graphic below shows my initial page load at the top, which can be ignored. Its the next 4 entries that show the issue. There are 3 POST requests which are my 3 ajax calls to update the DB, and the final GET which is the page refresh. The Page refresh GET fires after all 3 ajax calls have been sent, but it doesn't wait for the last ajax call to complete before it fires. As a consequence, it then gets old data as it completes before the previous ajac call has finished updating the database.

What am I doing wrong here?

回答1:

I recently applied something similar.

when() expects a deferred object or list of deferred objects, but if you want to use an array, you need to use apply().

replace

$.when(XHRs)

with

$.when.apply(null, XHRs)

If this does not work, you might need to wrap your Ajax call in a function:

function SendAjax(data){
return $.ajax({Options as they are in your ajax call});
}

and then push them to XHRs as such:

XHRs.push(SendAjax(data));

the following is how I implemented this in my code, you can adapt this if needed:

//We want to notify how many memberships have been made after they're all made. since they're async, we'll need to use promises
//however, because we repeat the same ajax call with different parameters, we need to push them to an array and then apply() them.
checkedBoxes.each(function () {
    createArray.push(CreateMembershipsAjax(this));
});
//we did the work before we start creating them, so show some progress;
add1ToProgress();
$.when.apply(null, createArray).done(function () {
    //this function will only start once all ajax calls have been successfull.
    divCreated.append(membershipCount + " memberships created:");
    MembershipsCreated = true;
    window.close();
});

...

CreateMembershipsAjax(element){
    //process element, create Data from it;
    return $.ajax({option});
}

And yes, the comments are actually in my code and not just added for clarification on this page.