jmdobry / angular-cache

angular-cache is a very useful replacement for the Angular 1 $cacheFactory.
http://jmdobry.github.io/angular-cache
MIT License
1.39k stars 156 forks source link

$http w/ cache is trying to store a promise, which dies on JSON.stringify #115

Closed intellix closed 10 years ago

intellix commented 10 years ago

Using Angular 1.2.17 I'm trying to use angularCache 2.3.5 with $http. my API call is returning 403 Forbidden, but the then() is always run despite being no cache.

After doing a little debugging, I traced it to angular.js calling cache.put(url, promise) on line 8209.

It seems Angular.JS attempts to store the promise in cache, which with localStorage, gets run through JSON.stringify during: _saveItemToStorage(key);, transforming the promise to just {}.

I believe this is documented as working in angularCache so something must have changed within one of the later releases of angular.js. I'll have a further look tomorrow as it's getting pretty late.

jmdobry commented 10 years ago

I can't find anything in Angular's changelog about this change. That's unfortunate.

I'm not sure how to reconcile a promise with localStorage.

jmdobry commented 10 years ago

https://github.com/jmdobry/angular-cache/releases/tag/2.3.6

Delagen commented 10 years ago

Does not work, store response object instead data. (use localStorage) On first request returns data because it is not in cache. On second full object as response with "config","status" and other fields where data is in "data" field.

intellix commented 10 years ago

Was just debugging this. If you use cache: true then inside the cachedRes looks like the below:

// angular.js:9349 - cache.put(url, [status, response, parseHeaders(headersString), statusText]);
cachedResp: Array[4]
    0: 200
    1: "{"name": "Dominic"}"
    2: Object
        content-type: "application/hal+json"
    3: "OK"

If you use angularCache, then the structure looks more like:

// angular-cache.js:790 - cache.put(key, v, options);
cachedResp: Object
    config: Object
    data: "{"name": "Dominic"}"
    status: 200
    statusText: "OK"

It seems angularCache is storing just the resolved value whereas angular.js stores an array of items. angularCache tests if it can store a promise (which just resolves the data) but angular.js one is specifically for $http requests

I suppose the fix looks like the below. I'm not sure how to do the unit tests for this to PR

// angular-cache.js:790
self.put(key, [v.status, v.data, v.headers(), v.statusText], options);
jmdobry commented 10 years ago

@intellix angular-cache can't just assume that the promise to be resolved is one created by an $http call. You could potentially put a promise from any library into angular-cache, and it will put the resolved value into the cache. How would you suggest that angular-cache detect that the resolved value is coming from $http?

jmdobry commented 10 years ago

Actually, refer to #116 for further discussion.