1

I was planning on making a service that caches server response data in AngularJS and this is what I did:

function addDataCachingServiceToModule(module) {
   module.factory('myDataCaching', function ($q, itemRepository) {

    var categoriesWithNewItems = undefined;

    function getCategoriesWithNewItems(date) {
        var deferred = $q.defer();
        if (!categoriesWithNewItems) {
            return itemRepository.getCategoriesWithNewItems(date)
                .then(function (res) {
                if (res.data.Data.Success) {
                    categoriesWithNewItems = res;
                    deferred.resolve(res);
                } else {
                    deferred.reject(res);
                }
            });
        } else {
            deferred.resolve(categoriesWithNewItems);
        }
        return deferred.promise;
    }

    function resetCategoriesWithNewItems() {
        categoriesWithNewItems = undefined;
    }

    return {
        getCategoriesWithNewItems: getCategoriesWithNewItems,
        resetCategoriesWithNewItems: resetCategoriesWithNewItems
    };
});
}

To my shock, it seems that while this works normally, when I try to use it like this:

myDataCaching.getCategoriesWithNewItems(date)
    .then(function(res2) {
            // res2 = undefined here !!!
    });

..I get undefined instead of the data that I pass in in deferred.resolve(res);.

I have debugged this and it calls the 1st deferred.resolve(res); in my service with valid data, but in my then() I get undefined instead.

It never passes through any of the other resolve()/reject() calls.

Does anyone have any idea what's wrong here?

3
  • 3
    why using two return statement, try removing return from 'return itemRepository.getCategoriesWithNewItems(date)' Commented Sep 22, 2014 at 9:52
  • @Anant Oh my...! Totally missed that... That was the problem. :( Commented Sep 22, 2014 at 9:53
  • :) it happens , good luck Commented Sep 22, 2014 at 9:56

1 Answer 1

2

So, Anant solved your missing return issue. Let's discuss how you won't have it any more in the first place :)

Promises chain, your current code has the deferred anti pattern which we'd rather avoid. You're creating excess deferred which you shouldn't. Your life can be a lot easier:

function addDataCachingServiceToModule(module) {
   module.factory('myDataCaching', function ($itemRepository) {

    var cats = null; // prefer null for explicit lack

    function getCategoriesWithNewItems(date) {
        // are we sure we don't want to cache by date? 
        return cats = (cats || itemRepository.getCategoriesWithNewItems(date))
    }

    function resetCategoriesWithNewItems() {
        categoriesWithNewItems = null;
    }

    return {
        getCategoriesWithNewItems: getCategoriesWithNewItems,
        resetCategoriesWithNewItems: resetCategoriesWithNewItems
    };
});
}

So, what did we do here:

  • Cache the promise and not the value to avoid race conditions. In your original version making multiple requests before the first one returned and then updating the cache multiple times which would have made deleting not work.
  • Avoid creating an excess deferred, this is faster and cleaner too.
Sign up to request clarification or add additional context in comments.

3 Comments

Nice! :) I have already changed mush of the code concerning your notice : cache by date ;)
Caching the promise didn't pass through my mind. :) Thanks. :)
If it makes you feel any better, I've done it tens of times and it didn't pass my mind either today when I wrote similar code today (in Swift). So your question probably saved me quite some time too :)

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.