我如何等待一组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) })
- iPhone – Grand Central调度主线程
- ASP.NET MVC4asynchronous控制器 – 为什么要使用?
- 在WebApi中使用HttpContext.Current是非常危险的,因为是asynchronous的
- 为什么我们需要在Redux中使用asynchronousstream的中间件?
- mocha before()中的asynchronous函数在it()spec之前完成了吗?
- 如何等待asynchronous方法来完成?
- 我将如何同步运行asynchronous任务<T>方法?
- Akka的好用例
- 如何find哪些promise在nodejs中未处理UnhandledPromiseRejectionWarning?