promises promesas example javascript angularjs

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); }); }

Ejemplo con esto en jsfiddle

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); }); }

Ejemplo en jsfiddle

Un poco más de lectura sobre diferidos y promesas.



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:

  1. El getAlbum está hecho para devolver una promesa.
  2. Recogiendo una promesa para cada iteración de la lista de getAlbums
  3. Una vez que se recogen todas las promesas, la matriz de promesas se pasa a $q.all
  4. 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.