我希望有一个for循环,每次迭代都会调用异步函数。
在for循环之后我想执行另一个代码块,但是在for循环中之前的所有调用都没有解决之前。
我目前的问题是,在所有异步调用完成之前执行for循环之后的代码块,或者根本不执行它。
带有FOR循环的代码部分和后面的代码块(完整代码,请参阅fiddle):
[..]
function outerFunction($q, $scope) {
var defer = $q.defer();
readSome($q,$scope).then(function() {
var promise = writeSome($q, $scope.testArray[0])
for (var i=1; i < $scope.testArray.length; i++) {
promise = promise.then(
angular.bind(null, writeSome, $q, $scope.testArray[i])
);
}
// this must not be called before all calls in for-loop have finished
promise = promise.then(function() {
return writeSome($q, "finish").then(function() {
console.log("resolve");
// resolving here after everything has been done, yey!
defer.resolve();
});
});
});
return defer.promise;
}
我创建了一个jsFiddle,可以在http://jsfiddle.net/riemersebastian/B43u6/3/找到。
目前看起来执行顺序很好(参见控制台输出)。
我的猜测是,这只是因为每个函数调用都会立即返回而不做任何实际工作。我试图用setTimeout延迟defer.resolve但是失败了(即从未执行过最后一个代码块)。你可以在小提琴中的outcommented块中看到它。
当我使用写入文件和从文件读取的实际函数时,最后一个代码块在最后一次写操作完成之前执行,这不是我想要的。
当然,错误可能出现在其中一个读/写函数中,但我想验证我在这里发布的代码没有任何问题。
答案 0 :(得分:118)
您需要使用的是$q.all,它将许多承诺合并为一个承诺,只有在所有承诺得到解决后才能解决。
在您的情况下,您可以执行以下操作:
function outerFunction() {
var defer = $q.defer();
var promises = [];
function lastTask(){
writeSome('finish').then( function(){
defer.resolve();
});
}
angular.forEach( $scope.testArray, function(value){
promises.push(writeSome(value));
});
$q.all(promises).then(lastTask);
return defer.promise;
}
答案 1 :(得分:3)
使用新的ES7,您可以更直接的方式获得相同的结果:
let promises = angular.forEach( $scope.testArray, function(value){
writeSome(value);
});
let results = await Promise.all(promises);
console.log(results);
答案 2 :(得分:0)
您可以使用$q
和&#39;减少&#39;在一起,将承诺联系在一起。
function setAutoJoin() {
var deferred = $q.defer(), data;
var array = _.map(data, function(g){
return g.id;
});
function waitTillAllCalls(arr) {
return arr.reduce(function(deferred, email) {
return somePromisingFnWhichReturnsDeferredPromise(email);
}, deferred.resolve('done'));
}
waitTillAllCalls(array);
return deferred.promise;
}
答案 3 :(得分:0)
这对我使用ES5语法
起作用了function outerFunction(bookings) {
var allDeferred = $q.defer();
var promises = [];
lodash.map(bookings, function(booking) {
var deferred = $q.defer();
var query = {
_id: booking.product[0].id,
populate: true
}
Stamplay.Object("product").get(query)
.then(function(res) {
booking.product[0] = res.data[0];
deferred.resolve(booking)
})
.catch(function(err) {
console.error(err);
deferred.reject(err);
});
promises.push(deferred.promise);
});
$q.all(promises)
.then(function(results) { allDeferred.resolve(results) })
.catch(function(err) { allDeferred.reject(results) });
return allDeferred.promise;
}