【问题标题】:Javascript Angular: how to chain unknown number of promisesJavascript Angular:如何链接未知数量的承诺
【发布时间】:2014-06-26 22:55:15
【问题描述】:

我正在编写一个 Angular.js 服务来提取一些 JSON 提要。最初,服务不知道要请求哪些/多少资源;它们依赖于另一个请求返回的 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);
                    }
               });
            }
        }
    }
});

谢谢。

【问题讨论】:

  • 你真的需要依次加载每个资源吗?如果没有,你能不只是触发多个请求,然后等待所有的承诺得到解决吗?
  • 您需要它们顺序执行还是可以并行运行?
  • 如果您正在考虑 Promise 链接,您应该查看 async/await。它会让你的生活更轻松

标签: javascript asynchronous promise


【解决方案1】:

如果您需要按顺序执行请求,您将创建一个可以用作链头的 Promise。然后,您可以将 $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;
        })
    };
});

但如果请求是并行 - 那么这将是更简单的解决方案。只是一个 promise 数组,然后调用 $q.all 函数等待解决所有的 promise。

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

【讨论】:

  • 我只是在寻找类似的东西,这真是太棒了 Oleksii。有点农民问题,但我当时试图将这些数据输入控制器并且遇到了麻烦。我可以在工厂的 $http 函数中 console.log 输出数据,但无法将 json 中的输出获取到控制器中的作用域 var 中。您对如何最好地做到这一点有什么建议吗?
  • 是的,基本上你需要在调用服务后使用 .then() 函数。我刚刚在我的答案中添加了带有示例的 plunker,看看它。
  • 太棒了,非常感谢 Oleksii,我真的很感激。我也刚刚赞成你的回答。感谢您的帮助。
  • 感谢您的回答!如果在链式 Promise 之后需要最后一步,您可以在后面添加一个额外的 resourcePromise.then(()=>{ finalWork();})。
  • 我不认为您的顺序示例实际上是顺序的。您需要重新分配承诺或使用 reduce()。
【解决方案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?

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2016-06-21
  • 2023-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 2019-05-24
  • 2019-07-23
相关资源
最近更新 更多