等待多个呼叫的最佳实践

时间:2015-06-25 17:39:25

标签: javascript jquery

我将此代码作为起点。

// $ = jQuery
// groupAdata and groupBdata are arrays 

function funcA(elem) {
    for (f = 0; f < groupAdata.length ; f++) {
        // this is an example on how this function calls other functions asynchronously. 
        elem.children('.partyA').each( function() {
            this.innerHTML = "been here" + groupAdata[f];
        });
    }
}

function funcB(elem) {
    // another function that fires more calls
    for (f = 0; f < groupAdata.length ; f++) {
        $.post(url, somedata, function(data) { 
            elem.children('.partyB').each( function() {
                this.innerHTML = "will be there" + groupBdata[f] + data;
            });
        }
    }
}

$(document).ready(function() {

    $('.groupA').each(function () {
        funcA(this);
    });

    $('.groupB').each(function (){
        funcB(this);
    });


});

function endofitall() {
    // call this after all instances of funcA and funcB are done.
}

运行endofitall()时,我想确保完成funcAfuncB的所有来电。

我认为Promises和jQuery.Deferred()将是一个很好/首选的方法,但无法将我找到的答案映射到这个特定的场景。 (它是模板工具的一部分,可为多个DOM元素触发多个dom操纵器func[AB]。)

2 个答案:

答案 0 :(得分:1)

在funcA和funcB的每次迭代中调用endofitall()。一旦计数器达到表示所有任务完成的数字,请保留一个计数器并执行实际工作。

function funcA(elem) {
    for (f = 0; f < groupAdata.length ; f++) {
        // these calls are not async
        elem.children('.partyA').each( function() {
            this.innerHTML = "been here" + groupAdata[f];
        });
        endofitall();
    }
}

function funcB(elem) {
    // another function that fires more calls
    for (f = 0; f < groupBdata.length ; f++) {
        $.post(url, somedata, function(data) { 
            elem.children('.partyB').each( function() {
                this.innerHTML = "will be there" + groupBdata[f] + data;
            });
            endofitall();
        }
    }
}

$(document).ready(function() {

    $('.groupA').each(function () {
        funcA(this);
    });

    $('.groupB').each(function (){
        funcB(this);
    });


});

var counter=0;
function endofitall() {
    if(++counter==groupAdata.length + groupBdata.length){
       //do stuff
}

答案 1 :(得分:1)

You can use $.when(). Your goal should be to get to: // call funcA, call funcB $.when( funcA(), funcB() ) // when everything is done go on with the callback .done(endofitall); In the case of funcA (synchronous function there's no problem and it will work as is). In the case of funcB (asynchronous) there are some things to consider. If it would be just one ajax call your code should be something like: // This function returns a promise. // When it's fulfilled the callback (in your case '.done(endofitall)') // will be called. function funcB(somedata){ return $.post(url, somedata); } As you are actually making more requests you have to return a resolved promise only when all calls have been fulfilled. // an *Asynchronous* function, returns an array of promises function funcB(elem, groupAdata) { var allCalls = []; // for each element in the array call the relative async // function. While you're calling it push it to the array. groupAdata.forEach(data, function(data){ allCalls.push( $.post(url, data) ); }); // allCalls is now an array of promises. // why .apply(undefined)? read here: https://stackoverflow.com/a/14352218/1446845 return $.when.apply(undefined, allCalls); } At this point you can go for a flat and clear: $.when( funcA(), funcB() ).done(endofitall); As a rule of thumb: if you are making async requests try to always return a promise from them, this will help flatten out your code (will post some link later on if you want) and to leverage the power of callbacks. The above code can surely be refactored further (also, I haven't used a lot of jQuery in the last few years, but the concept applies to any Js library or even when using no library at all) but I hope it will help as a starting point. References: $.when A similar answer here on SO