Comparison of AngularJS cache vs. browser HTTP cache

When working with Angular's $http service, one of the nifty options is a built-in cache service. It's off by default, and enabling this service can prevent repeated requests for the same resource. In this post, I'll compare Angular's service to native HTTP caching in your browser (I used Chrome as a baseline for comparison, and other browsers may differ slightly).

Angular $cacheFactory Browser HTTP cache (Chrome)
Storage Javascript heap memory (more) disk (more)
Eviction algorithm Least recently used (LRU) LRU (more)
Time-to-live until page refresh Determined by HTTP headers
Support for revalidation No Yes, with ETags
Requires cooperation of
remote server
No Yes
Example
$http({
  method: 'GET',
  cache: true,
  url: 'http://date.jsontest.com/
'})
Cache-Control: max-age=1800, private
Vary: Cookie
Content-Type: application/json
...

Overall, I'd say the browser has the advantage, but there are many gotchas to look out for with HTTP:

  • First, the server must be coorperating by sending suitable headers (usually easy if you control the remote resource, rare for third-parties).
  • If your resources require authenication, you'll need to set the Vary: header, and Cache-control: private. In the above example cookies are used, but other methods will work. For example if you authenticate with OAuth 2.0, the header would be Vary: Authorization.
  • Be careful with proxies, for example Varnish does not support "private" by default.
  • When using HTTPS, Chrome and Safari will not cache resources from servers with self-signed certificates. This sometimes makes testing more complicated.
  • Safari's implementation of Vary: is broken for cookies, and possibly other headers.

angular-cache

There is a third option if you can't solve the gotchas above, but need more flexibility: angular-cache. By using this replacement for $cacheFactory, you get more storage options (localStorage and sessionStorage), and a configurable time-to-live.

Filed under:

Comments

Thanks for the informative post!

We're developing an app with AngularJS and RESTful services. The data returned by services is changed infrequently and I very much would like to cache responses for a period of time. I'm setting Cache-Control: no-transform, max-age=604800 in the response.

Is there a way to have AngularJS JSON requests ($http/$resource) respect browser cache instead of using completely parallel built-in AngularJS cache or angular-cache library? From what I can see watching the network, by default $http requests are ignoring Cache-Control headers.

Cross-posted on StackOverflow: http://stackoverflow.com/questions/24943922/is-there-a-way-to-use-brows…

Yes, in our testing $http definitely honors cache-control headers. I'm not sure AngularJS could opt-out of browser caching, even if it wanted to, since under the hood it must use XMLHttpRequest().

As noted above, an invalid SSL cert will prevent caching. If that doesn't explain what you see, perhaps you could share a link to a sample endpoint URL? If there are other conditions that interfere with browser caching I'd love to know about it. Thanks!

Thanks a lot for your response! It was very useful. Now that I know that AngularJS fits into the browser cache, I've looked further into this. My services are all HTTP services, not HTTPS. Where I was stumbling was page reloads and the way they behave differently.

Let's divide use cases into two:

1. Page hit: simply going to a previously visited page.

Here I see what you see: most of the content is retrieved from cache. Chrome shows it better Firefox/Firebug. Firebug simply does not show cache hits in the Network panel.

2. Regular page reloads.

Pretty much all browsers have two shortcuts to refresh a page: regular reloads (Ctrl+R in Chrome/Windows) and
reloads ignoring cache (Shift+F5 in Chrome/Windows). I'm talking about regular reloads since if cache is ignored, there is nothing to discuss.

What seems to be happening is that browser issues If-Modified-Since requests for *all* resources on the page. The server then responds with 304 Not Modified for static resources and browser gets them from cache.

The issue is that we're not handling If-Modified-Since currently in our services. We simply set Cache-Control with the expiration age.

This is what I need to handle, and that should hopefully resolve the issue.

BTW, here is a background article on browser caching that I found quite useful: https://devcenter.heroku.com/articles/jax-rs-http-caching

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Ready for transformation?