0

i need some async data in a directive, this directive is repeated, so, when the app starts, each directive call the service data but because there is still no cached data, the $http is executed many times.

i added a promise inside the service and tried to return it instead of a new one. it seemed to work but i don't know if it is a good idea ?

    angular.module('test')
      .service('Users', function($q, $http) {

        var api = 'api';
        var cached = [];

        var localPromise;

        var _getAll = function() {

            if (localPromise) {

                return localPromise;
            }

            var deferred = $q.defer();
            if (cached.length > 0) {

                deferred.resolve(cached);
                localPromise = null;
                return deferred.promise;
            }

            var url = api + '/users';

            $http.get(url).then(function(data) {

                cached = data.data;
                deferred.resolve(cached);
                localPromise = null;
            }, function(err) {
                deferred.reject(err);
                localPromise = null;
            });
            localPromise = deferred.promise;
            return deferred.promise;
        }
        return {
            getAll: _getAll
        }
    });
awele
  • 35
  • 6

1 Answers1

0

You can, of course, cache the promise and return that to the next caller, except it could (probably should) be done without $q.defer - I'll get to that later.

Since your question is specific to $http, the easier approach would be to use the $http built-in cache with { cache: true } as the config:

app.factory("User", function($http){
  var svc = {
     getAll: function(){
       return $http.get("api/users", { cache: true })
                   .then(function(response){
                      return response.data;
                   });
     }
  };

  return svc;
})

If you want to cache the promise itself - useful when you do more than pure $http - you could do so and return that to the next caller. You don't need to use $q.defer since $http (or other promise-based API) already returns a promise, so just cache that. You can even use the $cacheFactory:

var usersCache = $cacheFactory("users");
svc.getUserDetails: function(userId){

   var promise = usersCache.get(userId) || 
                 $http.get("api/users/" + userId)
                      .then(doSomethingCrazy)
                      .then(doSomethingCrazier);

   usersCache.put(userId, promise);

   return promise;

}
New Dev
  • 48,427
  • 12
  • 87
  • 129