Search code examples
javascriptangularjsangular-promise

How to synchronise HTTP requests in angular application?


I've implemented a cacheService that has method get(url) which gets the value from HTTP, puts it to localStorage and returns $q promise. On the next .get(url) run it gets value from localStorage and returns it wrapped with $q.

function get(url){
    var saved = JSON.parse(localStorage.getItem(url));
    if (angular.isObject(saved)){
        return $q.when(saved);
    }
    return $http.get(url).then(function(xhr){
        localStorage.setItem(url, JSON.stringify(xhr.data));
        return xhr.data;
    });
}

Here's a case when my method doesn't work - it makes more than 1 HTTP request.

If I call cacheService.get(url) twice (e.g. from different modules):

  • when it runs first time, it doesn't find cache value in localStorage and makes the HTTP request
  • when it runs second time just after first one, first HTTP request isn't done yet and it's result value isn't cached yet. So my method makes HTTP request second time.

And I don't like it.

So the question is:

how to syncronise requests by url to have only 1 request per url?

UPD: I've got an idea:

  • define var currentRequests = {};
  • if localStorage has cached value, return the one
  • if currentRequests[url] is empty, do the request and set currentRequests[url] = $http.get(url) - store the promise in
  • if currentRequsts[url] isn't empty, then this request is running now, then just return currentRequests[url];

As JS is run in a single thread in browsers, currentRequests is thread-safe. But it isn't in nodejs. Correct?

What do you think about it?


Solution

  • It might be not that good solution. but you can give it a try.

    I'll suggest you to maintain the array of promises.

    var promiseArr = [];
    function get(url){
        var saved = JSON.parse(localStorage.getItem(url));
        if (angular.isObject(saved)){
            return $q.when(saved);
        }
        //check if $http request for the url has a pending promise.
        if(!promiseArr.hasOwnProperty(url)){          
          promiseArr[url] = $http.get(url).then(function(xhr){
              localStorage.setItem(url, JSON.stringify(xhr.data));
              delete promiseArr[url]; //Delete the promise once resolved.. please check.
              return xhr.data;
          });
        }
        return promiseArr[url]; //return the promise from the array.   
    }