Angularjs $ q.all

the*_*h92 104 promise angularjs q

我在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);
    }
Run Code Online (Sandbox Code Playgroud)

这是我的控制器调用服务:

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

})
Run Code Online (Sandbox Code Playgroud)

我认为在我的服务中设置$ q.all存在一些问题.

Ila*_*mer 222

在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);
})
Run Code Online (Sandbox Code Playgroud)
  • 当你var deferred= $q.defer();在for循环中写入它时,它被提升到函数的顶部,这意味着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);
}
Run Code Online (Sandbox Code Playgroud)

我最喜欢的方式是使用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);
}
Run Code Online (Sandbox Code Playgroud)

  • 好答案.一个补充:由于$ http本身返回promise,因此无需构造新的延迟.所以它可以更短:http://plnkr.co/edit/V3gh7Roez8WWl4NKKrqM?p = preview (14认同)
  • 喜欢使用`map`来建立一系列的承诺.非常简洁明了. (4认同)
  • 应该注意的是,声明被提升,但赋值保持在原来的位置。此外,现在还使用“let”语句进行块级作用域。请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let (2认同)

Zer*_*tin 35

$ http也是一个承诺,你可以使它更简单:

return $q.all(tasks.map(function(d){
        return $http.post('upload/tasks',d).then(someProcessCallback, onErrorCallback);
    }));
Run Code Online (Sandbox Code Playgroud)

  • 是的,接受的答案只是反模式的集合. (2认同)
  • 当然你可以省略then子句,我添加它以防你要记录所有HTTP请求,我总是添加它们并使用全局onError回调来处理所有服务器异常. (2认同)

Dav*_*yon 12

问题似乎是你正在添加deffered.promisewhen deffered本身就是你应该添加的承诺:

尝试更改为,promises.push(deffered);因此您不要将未包装的承诺添加到数组中.

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

            return $q.all(promises);
        }
Run Code Online (Sandbox Code Playgroud)

  • 文档还清楚地表明`$ q.all`得到的承诺不是延期对象.OP的真正问题在于范围界定,因为只有最后一个延迟才能得到解决 (4认同)