解决1个http请求中的多个promise

时间:2015-09-01 05:31:39

标签: javascript ajax angularjs promise

我当前的实现有多个控制器使用服务访问相同的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);

});

KenBurnsView示例。

假设请求的顺序并不重要,有没有更好的方法来执行此操作,或者是否存在可能潜伏在此技术中的任何缺陷?

2 个答案:

答案 0 :(得分:3)

你实际上并不需要多次承诺。您可以在同一回合中向每个呼叫者发出相同的承诺:

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

答案 1 :(得分:1)

代码看起来没问题,但我认为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;
      });
    }
  }
});