1. ホーム
  2. angularjs

[解決済み] Angularjs $q.all

2022-12-04 20:39:45

質問

angularjsで$q.allを実装したのですが、コードがうまく動きません。以下は私のコードです。

UploadService.uploadQuestion = function(questions){

        var promises = [];

        for(var i = 0 ; i < questions.length ; i++){

            var deffered  = $q.defer();
            var question  = questions[i]; 

            $http({

                url   : 'upload/question',
                method: 'POST',
                data  : question
            }).
            success(function(data){
                deffered.resolve(data);
            }).
            error(function(error){
                deffered.reject();
            });

            promises.push(deffered.promise);
        }

        return $q.all(promises);
    }

そして、これがサービスを呼び出す私のコントローラです。

uploadService.uploadQuestion(questions).then(function(datas){

   //the datas can not be retrieved although the server has responded    
}, 
function(errors){ 
   //errors can not be retrieved also

})

私のサービスでは、$q.allの設定に問題があるようです。

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

javascriptでは block-level scopes だけです。 function-level scopes :

この記事を読む javaScriptのスコープとホイスティング .

あなたのコードをどのようにデバッグしたかを見てください。

var deferred = $q.defer();
deferred.count = i;

console.log(deferred.count); // 0,1,2,3,4,5 --< all deferred objects

// some code

.success(function(data){
   console.log(deferred.count); // 5,5,5,5,5,5 --< only the last deferred object
   deferred.resolve(data);
})

  • と書くと var deferred= $q.defer(); と書くと と表示されます。 を関数の先頭に持ってくるということは、javascriptがこの変数を関数スコープ上で for loop .
  • 各ループで、最後の が遅延します。 が前のものを上書きする場合、そのオブジェクトへの参照を保存するブロックレベルのスコープは存在しません。
  • 非同期コールバック(成功/エラー)が呼び出されたとき、それらは最後の 遅延オブジェクト を参照し、それだけが解決されるので $q.allは決して解決されません なぜなら、それはまだ他の遅延オブジェクトを待っているからです。
  • 必要なのは、反復処理する各項目について無名関数を作成することです。
  • 関数はスコープを持つので、遅延オブジェクトへの参照は closure scope に保存されます。
  • #dfsq さんのコメントの通りです。http自体がプロミスを返すので、新しいディファードオブジェクトを手動で構築する必要はありません。

ソリューション angular.forEach :

デモのプランカーです。 http://plnkr.co/edit/NGMp4ycmaCqVOmgohN53?p=preview

UploadService.uploadQuestion = function(questions){

    var promises = [];

    angular.forEach(questions , function(question) {

        var promise = $http({
            url   : 'upload/question',
            method: 'POST',
            data  : question
        });

        promises.push(promise);

    });

    return $q.all(promises);
}

私の好きな方法は Array#map :

デモのプランカーです。 http://plnkr.co/edit/KYeTWUyxJR4mlU77svw9?p=preview

UploadService.uploadQuestion = function(questions){

    var promises = questions.map(function(question) {

        return $http({
            url   : 'upload/question',
            method: 'POST',
            data  : question
        });

    });

    return $q.all(promises);
}