我已经在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);
    }

这是我的 Controller ,它调用服务:
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 Scoping and Hoisting的文章。

看看我如何调试您的代码:

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);
})
  • 当您在for循环中编写var deferred= $q.defer();时,它的提升了到函数的顶部,这意味着javascript在for loop之外的函数范围内声明了此变量。
  • 在每个循环中,最后一个延迟的操作将覆盖前一个循环,没有块级作用域可保存对该对象的引用。
  • 调用异步回调(成功/错误)时,它们仅引用最后一个延迟对象,只有它得到解析,因此 $ q.all永远不会解析,因为它仍在等待其他延迟的对象。
  • 您需要为要迭代的每个项目创建一个匿名函数。
  • 由于函数确实具有作用域,因此即使执行了函数,对延迟对象的引用也会保留在 closure scope 中。
  • 如#dfsq所评论:由于$ http本身返回了promise,因此无需手动构造新的延迟对象。

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

    10-05 20:54
    查看更多