Caching a promise object in AngularJS service Caching a promise object in AngularJS service angularjs angularjs

Caching a promise object in AngularJS service


Is this the right approach?

Yes. The use of memoisation on functions that return promises a common technique to avoid the repeated execution of asynchronous (and usually expensive) tasks. The promise makes the caching easy because one does not need to distinguish between ongoing and finished operations, they're both represented as (the same) promise for the result value.

Is this the right solution?

No. That global data variable and the resolution with undefined is not how promises are intended to work. Instead, fulfill the promise with the result data! It also makes coding a lot easier:

var dataPromise = null;function getData() {    if (dataPromise == null)        dataPromise = $http.get("data.json").then(function (res) {           return res.data;        });    return dataPromise;}

Then, instead of loadDataPromise().then(function() { /* use global */ data }) it is simply getData().then(function(data) { … }).

To further improve the pattern, you might want to hide dataPromise in a closure scope, and notice that you will need a lookup for different promises when getData takes a parameter (like the url).


For this task I created service called defer-cache-service which removes all this boiler plate code. It writted in Typescript, but you can grab compiled js file. Github source code.

Example:

function loadCached() {   return deferCacheService.getDeferred('cacke.key1', function () {      return $http.get("data.json");   }); } 

and consume

loadCached().then(function(data) {//...});

One important thing to notice that if let's say two or more parts calling the the same loadDataPromise and at the same time, you must add this check

if (defer && defer.promise.$$state.status === 0) {   return defer.promise;}

otherwise you will be doing duplicate calls to backend.


This design design pattern will cache whatever is returned the first time it runs , and return the cached thing every time it's called again.

const asyncTask = (cache => {  return function(){    // when called first time, put the promise in the "cache" variable    if( !cache ){        cache = new Promise(function(resolve, reject){            setTimeout(() => {                resolve('foo');            }, 2000);        });    }    return cache;  }})();asyncTask().then(console.log);asyncTask().then(console.log);