【问题标题】:AngularJS: Avoid calling same REST service twice before response is receivedAngularJS:避免在收到响应之前两次调用相同的 REST 服务
【发布时间】:2015-01-15 21:43:46
【问题描述】:

我有两个指令,每个都使用同一个工厂包装 $q/$http 调用。

angular.module("demo").directive("itemA", ["restService", function(restService) {
    return {
        restrict: "A",
        link: function(scope, element, attrs) {
            restService.get().then(function(response) {
                // whatever
            }, function(response) {
               // whatever
            });
        }
    };
}]);


angular.module("demo").directive("itemB", ["restService", function(restService) {
    return {
        restrict: "A",
        link: function(scope, element, attrs) {
            restService.get().then(function(response) {
                // whatever
            }, function(response) {
               // whatever
            });
        }
    };
}]);

angular.module("demo").factory("restService", ["$http", "$q", function($http, $q) {
    return {
       get: function() {
           var dfd = $q.defer();
           $http.get("whatever.json", {
               cache: true
           }).success(function(response) {
              // do some stuff here
              dfd.resolve(response);
           }).error(function(response) {
              // do some stuff here
              dfd.reject(response);
           });
       }
    };
}]);

问题:当我这样做时

<div item-a></div>
<div item-b></div>

我启动了两次相同的 Web 服务,因为当 ItemB 的 GET 执行时,来自 ItemA 的 GET 仍在进行中。

有没有办法让第二个触发者知道已经有一个正在进行的请求,以便它可以等待一分钟并免费获取它?

我考虑过制作一个 $http 或 $q 包装器,将每个 URL 标记为待处理或未处理,但我不确定这是最好的方法。如果它处于未决状态,我会怎么做?只需返回现有的承诺,当另一个解决时它会解决?

【问题讨论】:

  • 也许您可以在控制器中调用一次服务并将对象传递给两个指令?

标签: javascript angularjs http asynchronous q


【解决方案1】:

是的,您需要做的就是缓存 Promise 并在请求完成后将其清除。中间的任何后续请求都可以使用相同的 Promise。

angular.module("demo").factory("restService", ["$http", "$q", function($http, $q) {
    var _cache;
    return {
       get: function() {
          //If a call is already going on just return the same promise, else make the call and set the promise to _cache
          return _cache || _cache = $http.get("whatever.json", {
               cache: true
           }).then(function(response) {
              // do some stuff here
              return response.data;
           }).catch(function(response) {
              return $q.reject(response.data);
           }).finally(function(){
              _cache = null; //Just remove it here
           });
      }
   };
}]);

【讨论】:

  • 这很有帮助。经过漫长的一天,我想我只是想不起来要回收我已经做出的承诺。我对其进行了一些修改,因为我们处于严格模式,但它是你所拥有的 90%。
  • @oooyaya cool.:) 如果您认为相关,请随时更新我的​​答案。
  • 不,你所拥有的一切都很好。有一件奇怪的事情。我们使用延迟模式,因此提供程序中的 .then 最终会通过 resolve 调用指令中的 .then。然而,使用 .finally(),顺序将是 provider 的 then,provider 的 finally,指令的 then - 所以,当指令的 then() 执行时,_dfd 被清除并且它爆炸了。所以,我们只是在提供程序中取消设置 _dfd,但在我们解决之后。我想有更好的方法,但这仅适用于 POC。
  • 在您的情况下,您根本不需要使用延迟模式。阅读this 并记住承诺链将按照注册时的确切顺序执行。
  • 我也很喜欢这个答案(尤其是在 cmets 中阅读材料),但我的 linter 在 return _cache || _cache = fn()。显然,在 return 语句中使用赋值是不好的做法(通常是模棱两可的)。只是挑剔,但 linter 不太可能(eslint.org/docs/rules/no-return-assign.html)。使用 return _cache 轻松修复 || (_cache = fn())。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-29
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 2016-01-04
  • 2014-06-20
  • 1970-01-01
相关资源
最近更新 更多