Alert is not defined in JSHint

Maybe you just started looking into jshint, or jsline for better JavaScript authoring, then when it comes to poorly debug or test something and you type alert(‘something’). This makes jshint unhappy, but can be useful sometimes, expecially if you have to debug something in old IE.

In jshit options the devel option allow you to use console.log and alerts without warnings. Personally I switch this setting only when really needed, to prevent annoying alerts or console logging in production.

Using effective promise caching in factories with AngularJS

I needed a way to cache the results from a factory, minimizing the number of requests server side. I started from a simple factory called User, which were simply fetching data from a remote resource:

myApp.factory('User', ['Restangular',
  function (Restangular) {

  return {
    getUser: function () {
    return Restangular.all('user').getList().then(function (user) {
      return user[0].email;
    });
    }
  };
  }
]);

Not really efficient: the user, which does not change during the session were fetched every time.

AngularJS provide the promise/deferred $q module, which allows much more modularity to our code. So my first real attempt to cache the result have been:

myApp.factory('User', ['Restangular', '$q',
  function (Restangular, $q) {
  var userCache;
  return {
    getUser: function () {
    var deferred = $q.defer();
    if (!userCache) {
      Restangular.all('user').getList().then(function (user) {
      userCache = user[0].email;
      deferred.resolve(user[0].email);
      });
    } else {
      deferred.resolve(userCache);
    }
    return deferred.promise;
    }
  };
  }
]);

The downside of this approach is that until the cache is not populated, every time this factory is called the request is performed any way. Because of that I was getting a number of server side requests, since I use this factory to fetch user permissions to display or hide components in my SPA UI.

I am been struggling with this problem, leading me to this question on StackOverflow.

In the end I figured out that is possible to build an array of promise objects, and resolve them all when the server side result is ready:

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

        if (promises.length > 0) {

          console.log('%cAdd to queue', 'color:orange;');
          promises.push(deferred);

        } else if (!userCache) {

          promises.push(deferred);
          console.log('%cFetch from live', 'color:red');
          Restangular.all('user').getList().then(function (user) {
            var i;
            userCache = user[0].email;
            for (i = promises.length; i--;) {
              console.log('%cYay! Resolving the existing promises with a single server side request', 'color:white;background:deepskyblue');
              promises.shift().resolve(userCache);
            }
          });

        } else {

          console.log('%cFetch direct from userCache', 'color:green');
          deferred.resolve(userCache);

        }

        return deferred.promise;

      }
    };
  }
]);

Let’s have a look at the code:

I define the two variables

var userCache, promises = [];

outside the returned object, to avoid subsequent overwrite of those variables.

The next step is to have a different promise for each request we get. So we define the deferred object inside the closure of our factory. Now we have to save that object, in order to be able to resolve it.

What we do is:

  1. If the promises array exists we add the new promise to the queue:

    if (promises.length > 0) { promises.push(deferred); }

  2. If the promises array is not populated (promises.length === 0) we check if the userCache variable contains some values. If it doesn’t then we have to fetch it from server side.
  3. The last scenario is when userCache exists, and then we can resolve the promise directly.

This list of steps misses something: when the promises added to the array are resolved?

Looking harder in what happens inside the fetch you can figure out yourself:

Restangular.all('user').getList().then(function (user) {
  var i;
  userCache = user[0].email;
  for (i = promises.length; i--;) {
    console.log('%cYay! Resolving the existing promises with a single server side request', 'color:white;background:deepskyblue;font-weight:bold;');
    promises.shift().resolve(userCache);
  }
});

When the server respond we resolve the chain of promises with the result just fetched, therefore minimizing the number of requests and improving the speed and user experience considerably.