小编典典

如何等待异步回调函数集?

javascript

我的代码在javascript中看起来像这样:

forloop {
    //async call, returns an array to its callback
}

在完成所有这些异步调用之后,我想计算所有数组的最小值。

我要如何等待所有人?

我现在唯一的想法是拥有一个名为done的布尔数组,并在第i个回调函数中将done [i]设置为true,然后说while(不是全部都完成了){}

编辑:我想一个可能但很丑陋的解决方案是在每个回调中编辑完了的数组,然后如果每个回调中都设置了所有其他完成,则调用一个方法,因此要完成的最后一个回调将调用继续方法。

提前致谢。


阅读 439

收藏
2020-04-25

共1个答案

小编典典

您对代码的了解不是很明确,所以我将提出一个方案。假设您有10个ajax调用,并且想要从这10个ajax调用中累积结果,然后在它们全部完成后就想做些什么。您可以通过在数组中累积数据并跟踪最后一个数据的完成时间来做到这一点:

手动计数器

var ajaxCallsRemaining = 10;
var returnedData = [];

for (var i = 0; i < 10; i++) {
    doAjax(whatever, function(response) {
        // success handler from the ajax call

        // save response
        returnedData.push(response);

        // see if we're done with the last ajax call
        --ajaxCallsRemaining;
        if (ajaxCallsRemaining <= 0) {
            // all data is here now
            // look through the returnedData and do whatever processing 
            // you want on it right here
        }
    });
}

注意:错误处理在这里很重要(未显示,因为它特定于您进行ajax调用的方式)。您将要考虑如何处理一个ajax调用永远不会完成的情况,该错误可能是由于错误或长时间卡住,或者很长时间后超时。


jQuery的承诺

在2014年为我添加了答案。这些天,promise通常用于解决此类问题,因为jQuery
$.ajax()已经返回了promise,并且$.when()将在一组promise全部解决后通知您,并会为您收集返回结果:

var promises = [];
for (var i = 0; i < 10; i++) {
    promises.push($.ajax(...));
}
$.when.apply($, promises).then(function() {
    // returned data is in arguments[0][0], arguments[1][0], ... arguments[9][0]
    // you can process it here
}, function() {
    // error occurred
});

ES6标准承诺

如kba的回答所指定:如果您的环境内置本机promise(现代浏览器或node.js或使用babeljstranspile或诺言polyfill),则可以使用ES6指定的诺言。请参阅此表以获取浏览器支持。除了IE,几乎所有当前的浏览器都支持Promise。

如果doAjax()返回承诺,则可以执行以下操作:

var promises = [];
for (var i = 0; i < 10; i++) {
    promises.push(doAjax(...));
}
Promise.all(promises).then(function() {
    // returned data is in arguments[0], arguments[1], ... arguments[n]
    // you can process it here
}, function(err) {
    // error occurred
});

如果您需要将非承诺异步操作变成返回承诺的异步操作,则可以像这样“承诺”它:

function doAjax(...) {
    return new Promise(function(resolve, reject) {
        someAsyncOperation(..., function(err, result) {
            if (err) return reject(err);
            resolve(result);
        });
    });
}

然后,使用上面的模式:

var promises = [];
for (var i = 0; i < 10; i++) {
    promises.push(doAjax(...));
}
Promise.all(promises).then(function() {
    // returned data is in arguments[0], arguments[1], ... arguments[n]
    // you can process it here
}, function(err) {
    // error occurred
});

Bluebird Promises

如果您使用功能更丰富的库(例如[Bluebird promise库),那么它将内置一些附加功能以使其更容易:

 var doAjax = Promise.promisify(someAsync);
 var someData = [...]
 Promise.map(someData, doAjax).then(function(results) {
     // all ajax results here
 }, function(err) {
     // some error here
 });
2020-04-25