Javascript Angular:如何链接未知数量的承诺

时间:2014-05-09 09:01:55

标签: javascript asynchronous promise

我正在编写一个Angular.js服务来提取一些JSON个Feed。最初,该服务不知道要请求的资源数量/数量;它们依赖于另一个请求返回的ID。

我很头疼地将$http服务请求链接在一起。有没有常用的模式来做到这一点?

我尝试过在另一个线程上建议的Array.reduce技术,但在同步ID和请求的数据时遇到了问题。

这是我到目前为止所拥有的。有没有人有任何建议?

aService.factory('dummy', function($http){
    // Dummy resources.
    var resources = [   
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js',
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js',
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js'
    ];
    return {
        data: function(callback){

            var jquerySources = []

            var promiseChain = $http({method: 'GET', url: resources[0]});
            var l = resources.length
            for (var i = 1; i < l; i++ ){
                promiseChain.then(function(data){

                    jquerySources.push({
                        url: resources[i],
                        source: data
                    });

                    promise_chain = $http({method: 'GET', url: resources[i]});
                    if (i === l){
                        return callback(jquerySources);
                    }
               });
            }
        }
    }
});

三江源。

2 个答案:

答案 0 :(得分:6)

如果您需要执行顺序请求,您可以创建一个可以用作链头的承诺。然后,您可以将$ http调用链接到该头部并解决头部承诺:

aService.factory('seq', function($http, $q){
    // Dummy resources.
    var resources = [   
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js',
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js',
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js'
    ];
    var deferred = $q.defer();
    var resourcePromise = deferred.promise;
    var res = [];
    angular.forEach(resources, function(resource){
      return resourcePromise.then(function(){
        return $http({ method: 'GET', url: resource });
      }).then(function(data){
        res.push({res: resource, data : data});
      });
    });

    deferred.resolve();

    return {
        getResource: resourcePromise.then(function(){
          return res;
        })
    };
});

但如果请求并行 - 那么这将是更简单的解决方案。只是一系列的承诺,只需调用$ q.all函数等待解决所有承诺。

aService.factory('par', function($http, $q){
    // Dummy resources.
    var resources = [   
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js',
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js',
      'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js'
    ];
    var promises = [];
    var res = [];
    angular.forEach(resources, function(resource){
      promises.push(
        $http({ method: 'GET', url: resource }).then(
          function(data){
            res.push({res: resource, data : data});
          })
        );
    });

    return {
        getResource: $q.all(promises).then(function(){
          return res;
        })
    };
});

另请注意,在这两种情况下,我们都有res数组来收集请求结果。

编辑: Plunker with example

答案 1 :(得分:2)

你确实可以通过reduce:

来做到这一点
var chain = resources.reduce(function (sourcesPromise, url) {
    return sourcesPromise.then(function (sources) {
        return $http({method: 'GET', url: url})
        .then(function (data) {
            sources.push({url: url, source: data});

            return sources;
        });
    });
}, $q.when([]));

chain.then(function (sources) {
    // [{url, source}, ...]
});

基于How to chain a variable number of promises in Q, in order?