我如何等待一组asynchronouscallback函数?

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

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

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

我怎么能等待所有的人?

我现在唯一的想法是有一个布尔型的数组叫做done,并在第i个callback函数中将done [i]设置为true,然后说(而不是全部完成){}

编辑:我想一个可能的,但丑陋的解决scheme,将编辑每个callback完成数组,然后调用一个方法,如果所有其他完成是从每个callback设置,因此最后一个callback完成将调用继续的方法。

提前致谢。

你的代码并不是非常具体,所以我将编写一个场景。 假设你有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 } }); } 

注意:error handling在这里很重要(没有显示,因为它是如何进行你的ajax调用)。 当一个Ajax调用永远不会完成,或者出现错误,或者被长时间卡住或者长时间超时,你会想要考虑如何处理这个事件。


jQuery的承诺

在2014年添加到我的答案。现在,承诺经常被用来解决这种types的问题,因为jQuery的$.ajax()已经返回一个承诺和$.when()会让你知道什么时候一组承诺都解决了,会收集你的回报结果:

 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的回答所指定的那样 :如果你有一个内置了native promise的环境(现代浏览器或者node.js,或者使用babeljs transpile或者使用promise polyfill),那么你可以使用ES6指定的promise。 请参阅此表以获取浏览器支持。 目前几乎所有的浏览器都支持Promise,IE除外。

如果doAjax()返回一个promise,那么你可以这样做:

 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 }); 

如果你需要做一个非诺言的asynchronous操作返回一个承诺,你可以像这样“promisify”:

 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 }); 

蓝鸟承诺

如果您使用更多的function丰富的库(如Bluebird承诺库) ,那么它内置了一些额外的function,以使其更容易:

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

你可以使用jQuery的Deferred对象和when方法。

 deferredArray = []; forloop { deferred = new $.Deferred(); ajaxCall(function() { deferred.resolve(); } deferredArray.push(deferred); } $.when(deferredArray, function() { //this code is called after all the ajax calls are done }); 

从2015年开始检查:我们现在在最新的浏览器 (Edge 12,Firefox 40,Chrome 43,Safari 8,Opera 32和Android 4.4.4和iOS Safari 8.4,但不包括Internet Explorer,Opera Mini和旧版本的Android)。

如果我们要执行10个asynchronous操作,并在完成所有操作后收到通知,我们可以使用原生Promise.all ,而不需要任何外部库:

 function asyncAction(i) { return new Promise(function(resolve, reject) { var result = calculateResult(); if (result.hasError()) { return reject(result.error); } return resolve(result); }); } var promises = []; for (var i=0; i < 10; i++) { promises.push(asyncAction(i)); } Promise.all(promises).then(function AcceptHandler(results) { handleResults(results), }, function ErrorHandler(error) { handleError(error); }); 

你可以像这样模拟它:

  countDownLatch = { count: 0, check: function() { this.count--; if (this.count == 0) this.calculate(); }, calculate: function() {...} }; 

那么每个asynchronous调用这样做:

 countDownLatch.count++; 

而在每个asynchronouscallback的方法结束时,你添加这一行:

 countDownLatch.check(); 

换句话说,你模仿一个倒计数锁存function。

这是我认为最简洁的方式。

Promise.all

FetchAPI

(出于某种原因,Array.map不适用于.then函数,但是你可以使用.forEach和[] .concat()或类似的东西)

 Promise.all([ fetch('/user/4'), fetch('/user/5'), fetch('/user/6'), fetch('/user/7'), fetch('/user/8') ]).then(responses => { return responses.map(response => {response.json()}) }).then((values) => { console.log(values); }) 

after一样使用控制stream库

 after.map(array, function (value, done) { // do something async setTimeout(function () { // do something with the value done(null, value * 2) }, 10) }, function (err, mappedArray) { // all done, continue here console.log(mappedArray) })