callback after async forEach AngularJS

后端 未结 4 485
一生所求
一生所求 2020-12-07 21:24

How do I add a callback function after an async forEach Loop?

Here is some better context:

$scope.getAlbums = function(user, callback) {
            


        
相关标签:
4条回答
  • 2020-12-07 21:48

    It looks like deferred http://docs.angularjs.org/api/ng.$q and specifically chaining promises could be useful here.

    0 讨论(0)
  • 2020-12-07 21:51
    $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;
        }
    

    In the above code:

    1. The getAlbum is made to return an promise.
    2. Collecting an promise for each iteration of the getAlbums list
    3. Once all the promises are collected, the promise array is passed to $q.all
    4. The $q.all method instead returns an final promise whose callback function will be triggered once all the promises in the array are resolved.
    0 讨论(0)
  • 2020-12-07 22:03

    As Andrew said usage of $q and the deferred object should allow you to accomplish your goal.

    You want to use $q.all() This will make sure all of your promise objects are resolved and then you can call your call back in .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

    Works but not with $http calls

    With the deferred object you gain access to a promise where you can change successive then() calls together. When you resolve the deferred object it will execute the foreach and then execute your call back function you supplied. I tried to simplify your example a bit further so it would work in 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

    A bit more reading on deferred and promises.

    0 讨论(0)
  • 2020-12-07 22:09

    Using the $resource promise PR commit slated for 1.1.3, I was able to wrap $resource calls with $q and control the flow of their async behavoir.

    $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);
    });
    
    0 讨论(0)
提交回复
热议问题