【问题标题】:Resolving multiple promises in 1 http request解决 1 个 http 请求中的多个承诺
【发布时间】:2015-11-26 06:01:05
【问题描述】:

我当前的实现有多个控制器使用服务访问同一个 JSON 数据集。我希望能够在单个查询中解决在进行中的 HTTP 请求期间传入的多个请求。

服务:

app.factory('dataService', function($http, $q) {
  var promises = [];
  var busy = false;
  return {
    getData: function() {
      if (busy) {
        var p = $q.defer();
        promises.push(p);
        return p.promise;
      }
      busy = true;
      var promise = $http.get('data.json').then(function(response) {
        while (promises.length > 0) {
          promises.pop().resolve(response.data);
        }
        busy = false;
        return response.data;
      }, function(error) {
        while (promises.length > 0) {
          promises.pop().reject(error);
        }
        busy = false;
      });
      return promise;
    }
  }
});

控制器:

app.controller('Ctrl1', function($scope, dataService) {
   $scope.logger = "";

   function getIt(a) {
     dataService.getData().then(function(d) {
      $scope.logger += 'Request '+a+': '+(new Date).getTime()+'\n';
   });
   }

   // These will be resolved in a 'batch'
   getIt(1);
   setTimeout(function(){getIt(2)},100);
   setTimeout(function(){getIt(3)},0);

   // This will be resolved in the 'next batch'
   setTimeout(function(){getIt(4)},2000);
   setTimeout(function(){getIt(5)},2100);

});

plunker 示例。

假设请求的顺序并不重要,有没有更好的方法来做到这一点,或者这种技术是否存在任何可能潜伏的缺陷?

【问题讨论】:

  • 这样做有什么特殊原因,请求不是已经缓存在浏览器中了吗?
  • 对不起,我的应用程序实际上并不要求静态 JSON,而是通过科尔多瓦的推送插件从角度广播中请求的实时数据馈送。显示的示例只是为了在具体实现中清晰

标签: javascript ajax angularjs promise


【解决方案1】:

您实际上并不需要在这里使用多个 Promise。您可以在同一回合向每个调用者发出相同的承诺:

app.factory('dataService', function($http, $q) {
  var busyPromise = null;
  return {
    getData: function() {
      if (!busyPromise) {
        busyPromise = $http.get('data.json').finally(function() {
          busyPromise = null;
        });
      }
      return busyPromise;
    }
  }
});

【讨论】:

  • 从来不知道可以共享承诺。这绝对简化了事情,谢谢!
  • 是的,你可以在一个 Promise 上拥有任意数量的处理程序——它们都会收到相同的值。 (你不应该有 0 个错误处理程序)
  • .finally() 有空吗?
  • @Roamer-1888:angular $q docs 简要提及。显然它在 1.2 中是新的,在 1.0 中不可用,并在 1.1 中命名为 .always
  • 情况变化很快。上次我看 $q 时只有.then(),没有别的。顺便说一句:很好的答案。
【解决方案2】:

代码看起来不错,但我认为defer 已被弃用,还要注意.then(success, fail) 反模式,例如,您为所有等待的承诺抛出错误,它会被隐藏以用于实际制作通话。所以我会把它改成这样的:

app.factory('dataService', function($http, $q) {
  var promises = [];
  var busy = false;
  return {
    getData: function() {
      if (busy) return new Promise((res, rej) => promises.push({res, rej}));
      busy = true;
      return $http.get('data.json').then(response => {
        promises.forEach( promise => promise.res(response.data));
        promises = [];
        busy = false;
      }).catch( e => {
        promises.forEach( promise => promise.rej(e));
        promises = [];
        busy = false;
        throw e;
      });
    }
  }
});

【讨论】:

  • 感谢您的提醒!
猜你喜欢
  • 1970-01-01
  • 2012-12-25
  • 2014-05-30
  • 1970-01-01
  • 1970-01-01
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 2016-12-23
相关资源
最近更新 更多