5

I am trying to avoid multiple ajax requests to the server in a factory. I already added a small caching service, but it is not enough for what I aim: this factory can be called several times before the server responds, causing the generation of multiple requests to the server.

To avoid this I added a second promise object, which if the AJAX request have been performed and the object is not yet in cache, than it should wait for a second promise to be resolved, but looks like I am missing something.

This is my code:

myApp.factory('User', ['Restangular', '$q',
  function (Restangular, $q) {
    var userCache, alreadyRun = false;
    return {
      getUser: function () {
        var deferred = $q.defer(), firstRun= $q.defer();

        if (!userCache && !alreadyRun) {
          alreadyRun = true;

          Restangular.all('user').getList().then(function (user) {
            console.log('getting user live ');
            userCache = user[0].email;
            firstRun.resolve(user[0].email);
          });
        } else if (!userCache && alreadyRun) {
          console.log('waiting for the first promise to be resolved ');
          firstRun.then(function(user) {
            console.log('resolving the promise');
            deferred.resolve(userCache);
          });

        } else {
          console.log('resolving the promise from the cache');
          deferred.resolve(userCache)
        }
        return deferred.promise;
      }
    };
  }
]);
1
  • I added my final implementation in the answers. Commented Mar 12, 2014 at 23:48

3 Answers 3

6

You could just return the original promise if the request has already been made. Something like this should work;

myApp.factory('User', ['Restangular', '$q',
  function (Restangular, $q) {
    var deferred = false;

    return {
      getUser: function () {

        if(deferred) {
          return deferred.promise;
        }

        deferred = $q.defer();

        Restangular.all('user').getList().then(function (user) {
          deferred.resolve(user[0].email);
        });

        return deferred.promise;
      }
    };
  }
]);

Also have a look at the Restangular documentation for caching requests

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for sharing @smilledge . In the meanwhile from when I asked the question I implemented something by myself. However your solution looks really clean and compact so I accepted your answer. Have a look at mine and let me know what you think of it :)
0

Everytime you run getUser, a new defer is created for firstRun. If it's already ran, you call firstRun.then, but that promise is never resolved.

3 Comments

But there is any way to achieve what am I trying to do?
Can't tell you without more context. GetUser is being called from a bunch of places at once? You can use Resolve on a route to make sure it's loaded before you start doing things.
Hi @JonathanRowny I added an answer with my own implementation, have a look and let me know what you think. I accepted as answer the one by smilledge because it looks really clean.
0

Thanks all for the answers, in the meanwhile I found a way to cache that particular factory:

.factory('User', ['Restangular', '$q',
  function (Restangular, $q) {
    var userCache, promises = [];
    return {

      getUser: function () {

        var deferred = $q.defer();

        if (promises.length > 0) {

          promises.push(deferred);

        } else if (!userCache) {

          promises.push(deferred);

          Restangular.all('user').getList().then(function (user) {
            var i;
            userCache = user[0];
            for (i = promises.length; i--;) {
              promises.shift().resolve(userCache);
            }
          });

        } else {

          deferred.resolve(userCache);

        }

        return deferred.promise;

      }
    };
  }
]);

Basically the idea is to create an array of promises while userCache is not ready, then resolve the whole queue once the request is ready and finally directly resolve the promise with the cached value for each future request.

I described the implementation of this promise caching here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.