如何在async forEach循环后添加回调函数?
以下是一些更好的背景信息:
$scope.getAlbums = function(user, callback) {
$scope.albumsList.forEach(function (obj, i) {
$scope.getAlbum(user, obj.id, function(value){
$scope.albums.push(value);
});
});
// callback(); ???
};
$scope.getAlbums('guy123', function(){
// forEach loop is all done!
console.log($scope.albums)
});
控制器:
.controller('Filters', ['$scope','Imgur', function($scope, Imgur) {
$scope.getAlbum = function(user, id, callback) {
Imgur.album.get({user:user, id:id},
function(value) {
return callback(value.data);
}
);
}
$scope.getAlbums = function(user, callback) {
// Callback function at end of this forEach loop?
// Request is async...
$scope.albumsList.forEach(function (obj, i) {
$scope.getAlbum(user, obj.id, function(value){
$scope.albums.push(value);
});
});
};
)]};
服务
.factory('Imgur', function($resource) {
return {
album : $resource('https://api.imgur.com/3/account/:user/album/:id')
}
});
答案 0 :(得分:45)
正如安德鲁所说,使用$q
和延迟对象可以让你实现目标。
您想使用$q.all()
这将确保您的所有承诺对象都已解决,然后您可以在.then()
function MyCtrl($scope, $q, $http) {
$scope.albumsList = [{
id: 1,
name: "11"
}, {
id: 2,
name: "22"
}
];
$scope.albums = [];
$scope.getAlbum = function(user, id, callback) {
return $http.get("https://api.imgur.com/3/account/" + user + "/album/" + id).success(
function(value) {
return callback(value.data);
}
);
}
$scope.getAlbums = function (user, callback) {
var prom = [];
$scope.albumsList.forEach(function (obj, i) {
prom.push($scope.getAlbum(user, obj.id, function(value){
$scope.albums.push(value);
}));
});
$q.all(prom).then(function () {
callback();
});
};
$scope.getAlbums('guy123', function () {
alert($scope.albums.length);
});
}
<强> Example with this on jsfiddle 强>
但$http
次来电
使用延迟对象,您可以访问承诺,您可以在其中一起更改连续的then()
个呼叫。解析延迟对象时,它将执行foreach,然后执行您提供的回调函数。我试图进一步简化你的例子,以便在jsfiddle中工作。
function MyCtrl($scope, $http, $q) {
$scope.albumsList = [{
id: 1,
name: "11"
}, {
id: 2,
name: "22"
}];
$scope.albums = [];
$scope.getAlbums = function (user, callback) {
var deferred = $q.defer();
var promise = deferred.promise;
promise.then(function () {
$scope.albumsList.forEach(function (obj, i) {
$scope.albums.push(obj);
});
}).then(function () {
callback();
});
deferred.resolve();
};
$scope.getAlbums('guy123', function () {
alert($scope.albums.length);
});
}
<强> Example on jsfiddle 强>
答案 1 :(得分:5)
$scope.getAlbums = function(user, callback) {
var promiseArr = [];
$scope.albumsList.forEach(function (obj, i) {
var anHttpPromise =
$scope.getAlbum(user, obj.id, function(value){
$scope.albums.push(value);
});
promiseArr.push(anHttpPromise);
});
$q.all(promiseArr).then(function(){
// This callback function will be called when all the promises are resolved. (when all the albums are retrived)
})
};
$scope.getAlbum = function(user, id, callback) {
var anHttpPromise = Imgur.album.get({user:user, id:id},
function(value) {
return callback(value.data);
}
);
return anHttpPromise;
}
在上面的代码中:
getAlbum
返回承诺。getAlbums
列表$q.all
$q.all
方法返回一个回调的最终承诺
一旦数组中的所有promise都被触发,函数将被触发
解决。答案 2 :(得分:4)
使用针对1.1.3设定的$resource
承诺PR commit,我能够使用$ q包装$resource
次调用并控制其异步行为的流程。
$scope.getAlbum = function(user, id, callback) {
var promise = Imgur.album.get({user:user, id:id}).$promise.then(
function( value ){
return callback(value.data);
},
function( error ){
//Something went wrong!
}
)
return promise;
}
$scope.getAlbums = function(user, callback) {
var prom = [];
$scope.albumsList.forEach(function (obj, i) {
var promise =
$scope.getAlbum(user, obj.id, function(value){
$scope.albums.push(value);
});
prom.push(promise);
});
$q.all(prom).then(function () {
callback();
});
};
$scope.getAlbums(user, function(){
// Totally works, bro.
console.log($scope.albums);
});
答案 3 :(得分:0)
看起来像延迟http://docs.angularjs.org/api/ng.$q,特别是链接承诺在这里很有用。