0

Hey on first $http requests I save my results in cache i am using two fucnctions in my controller calling the same function in service where is calling the $Http at first function for $Http it save the results in cache but for the second function when i tried to test it out wehter cache is empty or not it should not be empty as i already save results in my cache but it gives me

undefined error

Can Anyone tell what's going on wrong on my code

Here is the controller

    vm.getTopHotels =  function(){
     var hotelsLimit =  10;
     var top_hotels = 
     dataService.getHotels()
       .then(
          function(hotels){
             console.log(hotels);
             sortHotels = commonMethods.sortHotels(hotels.data.data,'Rating','SORT_DESC'); 
             hotelDetailsCheck = checkDetailsIfExists(sortHotels);
             //Get only top 10 hotels for home page
             top_hotels =  hotelDetailsCheck.slice(0,10);
             vm.topHotels =  top_hotels;
          },
          function(err){
             console.log(err);
          }); 
   };

  vm.getTopHotels();

   vm.getRHotels = function(){


    dataService.getHotels()
    .then(function(hotels){
         console.log('hotels recieced 2 ');
    },
    function(err){
       console.log(err);
    });
 }
 vm.getRHotels();

**dataService is Facotry here that is calling the $http methods ** for the vm.getTopHotels I'm saving results in the cache so getRHotels when call the $Http i am chcecking that if the cache is not empty it should retreive the data from the cache if not then it call the $Http request but for this function too it is calling the $http why? because i have already save the results in cache Can anybody tell me what is wrong?

Here is the dataService Code which is calling the $http methods and saving in Cache

(function(){  
    angular
       .module('app')
       .factory('dataService',DataFactory);

       DataFactory.$inject = ['$http','$q','$cacheFactory']

       function DataFactory($http,$q,$cacheFactory){

          var cache = $cacheFactory('localCache');

          var service = {
              getHotels:getHotels
          };
           return service;


         function getHotels(){
          var def = $q.defer();
          var hotelsData = cache.get('hotelsData');
          console.log(hotelsData);
         if(!hotelsData){

             $http.get('/hotels/getHotelsData')
               .then(
                 function successCallback(data){
                   cache.put('hotelsData',data.data);
                //   service.hotels =  data.data;
                   def.resolve(data);
                 },
                 function errorCallback(data){
                    def.reject('Failed to retrieve hotels');
                 });

               return def.promise;
           }else{
            console.log('cached');
           }
          }


       }

})();
georgeawg
  • 48,608
  • 13
  • 72
  • 95

2 Answers2

0

You can actually specify $http to cache results by adding cache:true to your config object.

function getHotels() {
  return $http.get('/hotels/getHotelsData', {cache:true});
}

You can read more about the $http config here:https://docs.angularjs.org/api/ng/service/$http

Also to clarify, $q.defer is a helper that alows you to wrap non promise API callbacks as promises. $http returns a promise. You can just return the response of $http.get and perform a .then on it.

If you need to manipulate the data before returning it, you still don't need to wrap it within $q.defer()

function getHotels() {
  return $http.get('/hotels/getHotelsData', {cache:true})
  .then(function(response){
    response.data[0].hotelName = 'changedName';
    return response;
  })
}
cody mikol
  • 811
  • 7
  • 21
  • so for setting cache to true it will not cal the $http get request from the backend ? – Creative Developers Sep 18 '19 at 11:27
  • I'm using $q.defer because i need to use in async is that right ? – Creative Developers Sep 18 '19 at 11:28
  • It will make one http request and cache the result. Any further http requests to the same resource will not make an http request, just return the cached value. Also no, $http.get() returns a promise that you can call .then on and so does $q.defer. You're basically unwrapping the $http promise and rewrapping it into a $q.defer() promise. This is redundant and accomplishes nothing. – cody mikol Sep 18 '19 at 13:12
  • For your second question, see the response to this post https://stackoverflow.com/questions/30750207/is-this-a-deferred-antipattern – cody mikol Sep 18 '19 at 13:14
0

The getHotels function has a race condition: A second call to the function before the data returns from the server will allow a second HTTP GET request.

Since the $http service immediately returns a promise, it is better to cache that promise.

 var hotelsPromise = null;

 function getHotels(){
     if (hotelsPromise) return hotelsPromise;
     //ELSE
     hotelsPromise = $http.get('/hotels/getHotelsData')
       .then(function successCallback(response){
         return response.data;
     },
         function errorCallback(response){
             throw 'Failed to retrieve hotels';
     });
     return hotelsPromise;
 }

This will avoid erroneous multiple HTTP GET requests.

georgeawg
  • 48,608
  • 13
  • 72
  • 95