Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: Avoid calling same REST service twice before response is received

I have two directives, each consuming the same factory wrapping a $q/$http call.

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

Problem: When I do this

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

I get the same web service fired off twice, because the GET from ItemA is still in progress when the GET for ItemB goes.

Is there a way for whichever fires second to know that there's already a request to this in progress, so that it can wait a minute and grab it for free?

I've thought about making an $http or $q wrapper which flags each URL as pending or not but I'm not sure that's the best way. What would I do if it was pending? Just return the existing promise and it'll resolve when the other resolves?

like image 798
oooyaya Avatar asked Jan 15 '15 21:01

oooyaya


1 Answers

Yes, all you need to do is to cache the promise and clean it off after the request is done. Any subsequent request in between can just use the same 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
           });
      }
   };
}]);
like image 116
PSL Avatar answered Oct 14 '22 15:10

PSL