20

非同期 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')
    }
});
4

4 に答える 4

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

jsfiddle でのこれの例

$http機能しますが、通話では機能しません

then()遅延オブジェクトを使用すると、連続する呼び出しを一緒に変更できる promise にアクセスできます。遅延オブジェクトを解決すると、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);
    });
}

jsfiddle の例

deferred と promises についてもう少し読んでください。

于 2013-05-08T00:11:59.060 に答える