cod*_*ple 92 javascript asynchronous
我的代码在javascript中看起来像这样:
forloop {
//async call, returns an array to its callback
}
Run Code Online (Sandbox Code Playgroud)
在完成所有这些异步调用之后,我想计算所有数组的最小值.
我怎么能等他们全部?
我现在唯一的想法就是有一个名为done的布尔数组,并在第i个回调函数中将done [i]设置为true,然后说while(并非所有都已完成){}
编辑:我想一个可能的,但丑陋的解决方案,就是在每个回调中编辑完成数组,然后如果从每个回调设置所有其他完成后调用一个方法,那么最后一个回调完成将调用continue方法.
提前致谢.
jfr*_*d00 184
你的代码并不是很具体,所以我会编写一个场景.假设您有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
}
});
}
Run Code Online (Sandbox Code Playgroud)
注意:错误处理在这里很重要(未显示,因为它特定于您如何进行ajax调用).当一个ajax调用永远不会完成时,您将需要考虑如何处理这种情况,无论是出现错误还是长时间停滞或长时间停留.
jQuery承诺
在2014年添加我的答案.现在,承诺通常用于解决此类问题,因为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
});
Run Code Online (Sandbox Code Playgroud)
ES6标准承诺
正如kba的答案所述:如果你有一个内置本机promises的环境(现代浏览器或node.js或使用babeljs transile或使用promise polyfill),那么你可以使用ES6指定的promises.有关浏览器支持,请参阅此表.几乎所有当前浏览器都支持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
});
Run Code Online (Sandbox Code Playgroud)
如果你需要对一个返回promise的非同步异步操作,你可以像这样"promisify"它:
function doAjax(...) {
return new Promise(function(resolve, reject) {
someAsyncOperation(..., function(err, result) {
if (err) return reject(err);
resolve(result);
});
});
}
Run Code Online (Sandbox Code Playgroud)
然后,使用上面的模式:
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
});
Run Code Online (Sandbox Code Playgroud)
蓝鸟承诺
如果您使用功能更丰富的库(如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
});
Run Code Online (Sandbox Code Playgroud)
kba*_*kba 14
从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个异步操作并在完成后获得通知,我们可以使用本机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);
});
Run Code Online (Sandbox Code Playgroud)
Pau*_*aul 10
您可以使用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
});
Run Code Online (Sandbox Code Playgroud)
你可以像这样模仿它:
countDownLatch = {
count: 0,
check: function() {
this.count--;
if (this.count == 0) this.calculate();
},
calculate: function() {...}
};
Run Code Online (Sandbox Code Playgroud)
然后每个异步调用执行此操作:
countDownLatch.count++;
Run Code Online (Sandbox Code Playgroud)
而在每个asynch回调的方法结束时,你添加这一行:
countDownLatch.check();
Run Code Online (Sandbox Code Playgroud)
换句话说,您可以模拟倒计时锁存功能.
我认为这是最整洁的方式。
(由于某种原因,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);
})
Run Code Online (Sandbox Code Playgroud)