-->

use jquery deferreds for variable number of ajax r

2020-03-26 09:49发布

问题:

when I have a variable number of ajax requests, how can I call them using deferreds?

my guess:

//qty_of_gets = 3;

function getHTML(productID, qty_of_gets){

    var dfd = $.Deferred(),
            i = 0,
            c = 0;

    //this is where there could be some magic to 
    //do multiple ajax posts
    //obviously I'm out of my depth here...
    while (i <= qty_of_gets){

        dfd.pipe(function(){
            $.get("queries/html/" + product_id + i + ".php");
        });                       
    i++
    }
    dfd.done(function(){

        while (c <= qty_of_gets){
           $('myDiv').append(c);
           c++;
        }

    });
}

回答1:

If you want to execute the Ajax calls sequentially, you have to return the promise from the callback and also attach a new callback to the last promise object:

var dfd = $.Deferred(),
   promise = dfd.promise(),
   i = 0,
   c = 0;

while (i <= qty_of_gets) {
    // needs an IIFE
    (function(i)
        promise = promise.then(function(){
            return $.get("queries/html/" + product_id + i + ".php");
        });
    }(i++));                       

}

promise.done(function(){

    while (c <= qty_of_gets){
       $('myDiv').append(c);
       c++;
    }

});

// resolve deferred
dfd.resolve();

As of jQuery 1.8, you should use .then instead of .pipe.

Another problems is (in your example at least) that at the time the callbacks are executed, i won't have the value you expect. You can use an immediately invoked function expression to capture the current value of i. See JavaScript closure inside loops – simple practical example for more info.


There is no clean solution for getting the results. I think the best you could do is adding the results to an array and access that array in the .done callback. I.e.:

var results = [];

while (i <= qty_of_gets) {
    // needs an IIFE
    (function(i)
        promise = promise.then(function(){
            return $.get("queries/html/" + product_id + i + ".php")
                     .then(function(result) {
                       results[i] = result;
                     });
        });
    }(i++));                       

}

promise.done(function(){
    // do something with `results`
});


回答2:

Close, you need to return a promise object from the .pipe callback.
See felix's answer, the next sample has additional issues than just the return missing.

dfd.pipe(function(){
    return $.get("queries/html/" + product_id + i + ".php");
});  

also, I don't think it's actually written anywhere yet, but .pipe is implemented like this in the core in recent versions:

promise.pipe = promise.then

therefore, you could should replace dfd.pipe with dfd.then
Reference: http://api.jquery.com/deferred.pipe/

An alternative as adeneo mentioned is to use $.when

function getHTML(productID, qty_of_gets) {

    var dfdArr = [];

    while (i <= qty_of_gets) {
        dfdArr.push($.get("queries/html/" + product_id + i + ".php"));
        i++
    }
    $.when.apply(null, dfdArr).done(function () {

        for (response in arguments) {
            $('#myDiv').append(response[0]);
        }

    });
}