5

My service needs to retrieve a value asynchronously, but once I have it, I'd like to used a cached version of the value.

When two controllers call this service, I'd expect the first one to cache the retrieved value and the second one to use the cached value, but according to the log, I never find a cached value. When this runs, I see a log message that shows the value being cached, then, when I follow an angular route to a different controller, I do not see that the service finds the cached value. Why does it not run according to my expectation**?**

angular.module('myApp.services').factory('Config', function() {

    var Config = { };

    Config.currentYear = function() {
        if (Config._currentYear) {
            // sadly, we never execute here
            console.log("returning cached year");
            return Parse.Promise.as(Config._currentYear);
        }
        return Parse.Config.get().then(function(config) {
            console.log("caching year");
            Config._currentYear = config.get("currentYear");
            return Config._currentYear;
        });
    };

    return Config;

});

A couple notes: (1) I named the cached attribute _currentYear, adding the underscore to avoid colliding with the function name. Not sure if I need to do that. (2) I return a fulfilled promise when the value is cached, so the function always returns a promise...also not sure if that's needed, but figure it can't hurt.

PSL
  • 123,204
  • 21
  • 253
  • 243
user1272965
  • 2,814
  • 8
  • 29
  • 49
  • 2
    So what is the problem exactly? – dfsq Jan 02 '15 at 20:52
  • Its was stated in the question right under the code. I moved the question part to above the code – user1272965 Jan 02 '15 at 20:55
  • Checked other similar questions? http://stackoverflow.com/questions/15100020/using-angular-service-to-share-data-between-controllers – blurfus Jan 02 '15 at 20:59
  • You did not state a question anywhere. This is already quite clear from the lack of a question mark. However, if you do not get a cache hit, it might simply be because `Config._currentYear` is not assigned some value until after both calls have been executed (i.e. then then() function returns a promise, so both calls might already be at `Parse.Config.get()` before a new value is assigned.) – dirkk Jan 02 '15 at 21:01
  • @ochi in suggested duplicate, the answer appears to be that the cached value was getting lost when the page reloads. My app is using angular routing and the problem occurs without reloading the page. – user1272965 Jan 02 '15 at 21:09
  • @dirkk added a question mark. also, since i see a log message indicating that the value is cached, i don't think the problem is caused by a race condition, running the get() again too soon. – user1272965 Jan 02 '15 at 21:13

1 Answers1

3

Instead of caching the data, why don't you just cache the promise and return it. When you cache the data, you are setting the data Config._currentYear only within the success callback and there are chances that other subsequent call(s) happening before the success callback is run. So you end up making the same call again. You can easily see this when you have calls made to the same service method from different controllers which are instantiated, by their presence on the same template. Caching a promise upfront will avoid these issues.

angular.module('myApp.services').factory('Config', function() {
    var config; //Just use to save the promise
    Config.currentYear = function() {
        /*If there is already a call made before return the promise else
          make the actual call and store the promise in the variable.*/
        return config || config = Parse.Config.get().then(function(config) {
            return config.get("currentYear");
        });
    };
});
PSL
  • 123,204
  • 21
  • 253
  • 243
  • 2
    1) thanks for the answer, 2) great idea to cache the promise to avoid the race condition (I am going to use that in other places, too), 3) I just discovered that my problem had to do with adobe brackets nodejs server (when I ran one manually, it worked), but I am going to mark this correct since its helpful (and not pedantic about placing question marks in the question). – user1272965 Jan 02 '15 at 21:40
  • @user1272965 You are welcome. Glad it was of some help. One more thing you can add is to nullify the cached promise in the catch block. Just so you dont always keep the failed promise in the cache. And yes caching the promise reduces the number of lined of code which otherwise you have to do when caching the data, after all promise is just a proxy for data. – PSL Jan 02 '15 at 21:42
  • @user1272965 I am sorry if you think I (and others) are being pedantic. This might seem so to you, but it is merely because we made a number of experiences when people didn't quite cleared asked what their problem is and people spend (useless) time to solve a problem that didn't exist. So being _very_ clear here is hopeful and I hope you do not get biased against the SO community. But I am glad PSL also thought that the race condition is the core of the problem :) – dirkk Jan 02 '15 at 22:11