1. ホーム
  2. angularjs

angular $q, for-loopの中と後に複数のプロミスを連鎖させる方法

2023-11-24 11:44:51

質問

反復毎に非同期関数を呼び出すforループを持ちたいのですが、どうすればいいですか?

forループの後、別のコードブロックを実行したいのですが、forループの前の呼び出しがすべて解決される前ではありません。

現時点での私の問題は、forループの後のコードブロックが、すべての非同期呼び出しが終了する前に実行されるか、まったく実行されないかのいずれかであることです。

FORループのコード部分とそのあとのコードブロック(完全なコードについては フィドル ):

[..]
function outerFunction($q, $scope) {
    var defer = $q.defer();    
    readSome($q,$scope).then(function() {
        var promise = writeSome($q, $scope.testArray[0])
        for (var i=1; i < $scope.testArray.length; i++) {
             promise = promise.then(
                 angular.bind(null, writeSome, $q, $scope.testArray[i])
             );                                  
        } 
        // this must not be called before all calls in for-loop have finished
        promise = promise.then(function() {
            return writeSome($q, "finish").then(function() {
                console.log("resolve");
                // resolving here after everything has been done, yey!
                defer.resolve();
            });   
        });        
    });   

    return defer.promise;
}

jsFiddleを作成しましたので、こちらをご覧ください。 http://jsfiddle.net/riemersebastian/B43u6/3/ .

今のところ、実行順序は問題なさそうです(コンソール出力をご覧ください)。

私の推測では、これは単に、すべての関数呼び出しが実際の仕事をすることなく即座に戻るためです。私は、setTimeout を使用して defer.resolve を遅らせようとしましたが、失敗しました (つまり、最後のコード ブロックは決して実行されませんでした)。フィドルのアウトコメントされたブロックで見ることができます。

ファイルへの書き込みとファイルからの読み取りを行う実際の関数を使用すると、最後のコードブロックは最後の書き込み操作が終了する前に実行され、これは私が望むものではありません。

もちろん、エラーはそれらの読み取り/書き込み関数のうちの1つである可能性がありますが、私はここに投稿したコードに何も問題がないことを検証したいと思います。

どのように解決するのですか?

使用する必要があるのは $q.all で、これはいくつかの約束をひとつにまとめ、すべての約束が解決されたときにのみ解決されます。

あなたの場合、次のようなことをすることができます。

function outerFunction() {

    var defer = $q.defer();
    var promises = [];

    function lastTask(){
        writeSome('finish').then( function(){
            defer.resolve();
        });
    }

    angular.forEach( $scope.testArray, function(value){
        promises.push(writeSome(value));
    });

    $q.all(promises).then(lastTask);

    return defer.promise;
}