javascript - promesas - promise angular 6
devoluciĆ³n de llamada despuĆ©s de async para cada AngularJS (4)
¿Cómo agrego una función de devolución de llamada después de un async forEach Loop?
Aquí hay un mejor contexto:
$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)
});
Controlador:
.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);
});
});
};
)]};
Servicio:
.factory(''Imgur'', function($resource) {
return {
album : $resource(''https://api.imgur.com/3/account/:user/album/:id'')
}
});
Como dijo Andrew, el uso de $q
el objeto diferido debería permitirle lograr su objetivo.
Desea usar $q.all()
Esto asegurará que todos los objetos de su promesa se hayan resuelto y luego podrá devolver su llamada en .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);
});
}
Funciona pero no con $http
llamadas $http
Con el objeto diferido, obtiene acceso a una promesa en la que puede cambiar juntas las llamadas sucesivas then()
. Cuando resuelva el objeto aplazado, ejecutará el foreach y luego ejecutará la función de devolución de llamada que proporcionó. Intenté simplificar un poco más su ejemplo para que funcionara en 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);
});
}
Parece que las http://docs.angularjs.org/api/ng.$q diferidas y específicamente las promesas de encadenamiento podrían ser útiles aquí.
Usando el compromiso de PR de $resource
prometido programado para 1.1.3, pude envolver $resource
llamadas de $resource
con $ qy controlar el flujo de su comportamiento asíncrono.
$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);
});
$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;
}
En el código anterior:
- El
getAlbum
está hecho para devolver una promesa. - Recogiendo una promesa para cada iteración de la lista de
getAlbums
- Una vez que se recogen todas las promesas, la matriz de promesas se pasa a
$q.all
- El método
$q.all
devuelve una promesa final cuya función de devolución de llamada se activará una vez que se hayan resuelto todas las promesas de la matriz.