1

I have written a function wrapper that returns cached values for HTTP responses. In a specific situation (marked by comment // <--HERE) I see inconsistent behavior. I'm frankly not sure what exactly the inconsistency is, but bottom line, when the cache expires (has_expired), it does not wait for the http get to return in the recursive call.

My guess is I haven't put a "return" somewhere on a promise but I can't find out where (and why). Do I need to put a return in front of localForage.removeItem (and if so why?)

function cache_or_http(url,key) {

    if (dont_use_cache()) {
      return $http.get(url);
    }
    var d = $q.defer();
    localforage.getItem(key)
    .then (function(data) {
         if (data) { // exists
            if (has_expired(data.created_at)) {
                localforage.removeItem(key)
                .then (function() {return cache_or_http(url,key);}) // <--HERE
                .catch(function() {return do_error_handling();})
            } else { // not expired
                 d.resolve(JSON.parse(data.value));
                 return d.promise;
             }
         } else {
            // doesn't exist
            return $http.get(url)
            .then (function(data) {
                cache_entry = {
                    'value': JSON.stringify(data),
                    'created_at': moment().toString()
                };
                localforage.setItem(key, cache_entry);
                d.resolve(data);
                return (d.promise);
            });
         } // doesn't exist
    }); // getItem .then
    return (d.promise);
 }
user1361529
  • 2,667
  • 29
  • 61

1 Answers1

1

There is no need to manufacture a new promise with $q.defer. The .then method of a promise already returns a promise.

function cache_or_http(url,key) {
    ̶v̶a̶r̶ ̶d̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶
    ̲r̲e̲t̲u̲r̲n̲ localforage.getItem(key)
    .then (function(data) {
         if (data) { // exists
            if (has_expired(data.created_at)) {
                ̲r̲e̲t̲u̲r̲n̲ localforage.removeItem(key)
                .then (function() {return cache_or_http(url,key);}) // <--HERE
                .catch(function() {return do_error_handling();})
            } else { // not expired
                 ̶d̶.̶r̶e̶s̶o̶l̶v̶e̶(̶J̶S̶O̶N̶.̶p̶a̶r̶s̶e̶(̶d̶a̶t̶a̶.̶v̶a̶l̶u̶e̶)̶)̶;̶ 
                 return JSON.parse(data.value);
            }
         } else {
            // doesn't exist
            return $http.get(url)
            .then (function(data) {
                cache_entry = {
                    'value': JSON.stringify(data),
                    'created_at': moment().toString()
                };
                ̲r̲e̲t̲u̲r̲n̲ localforage.setItem(key, cache_entry);
                ̶d̶.̶r̶e̶s̶o̶l̶v̶e̶(̶d̶a̶t̶a̶)̶;̶
                ̶r̶e̶t̶u̶r̶n̶ ̶(̶d̶.̶p̶r̶o̶m̶i̶s̶e̶)̶;̶
            });
         } // doesn't exist
    }); // getItem .then
    ̶r̶e̶t̶u̶r̶n̶ ̶(̶d̶.̶p̶r̶o̶m̶i̶s̶e̶)̶;̶
 }

For more information, see

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Thank you. I understand I was needlessly wrapping things around additional promises. For my understanding, putting aside the part about additional wraps, is there an error with my code? – user1361529 Oct 23 '20 at 11:07
  • I've also added a small if situation in my original code (no cache setting) that further confuses me - I think in this case, I do need my own promise wrapper? – user1361529 Oct 23 '20 at 11:42
  • Okay, I wrote up a fiddle using your suggestion http://jsfiddle.net/mj9vchnr/11/ - seems to work fine, but in my own code, I'm facing issues. I'll need to dive in deeper into what is going on. Thanks. – user1361529 Oct 23 '20 at 14:18
  • found the issue - was in my code, unrelated to your suggestion – user1361529 Oct 23 '20 at 14:44
  • Do I need to make sure the first line in the function is a return? Please see my modified code. It works but I’ve read the entire code should be wrapped in return. – user1361529 Oct 24 '20 at 00:52