24

The idea is to make use of HTML5 local storage to store frequently accessed CSS and JavaScript.

For example (pseudo-code):

var load_from_cdn = true;
if (detect local storage)  
{
  if (cache of css, js found)
  {
     load the local storage cache
     load_from_cdn = false;
  }
}
if (load_from_cdn)
{
   document.write('<script>...');
}

Is this possible or realistic?

I do aware browser cache, there will be still some header access checking,
I assuming no HTTP access is better (in my thinking)

PS : It seems that local storage only support key-value pair, can someone prove it ?
(best with some examples)

5

7 Answers 7

11

It is absolutely OK to use local storage to store JS and CSS. However, local storage has 5M per domain limitation. You might have to reconsider this strategy.

For desktop web, you can leverage default browser cache to do the trick. Just set the JS & CSS HTTP response to be cacheable. It is simple and easy.

For mobile web, latency is high. So, reducing HTTP requests is critical. So, having JS & CSS in external URL's is optimal. It would be much better to have JS & CSS inline. This reduce HTTP requests, but bloated the HTML content. Then What? Just as you said, use local storage!

When one browser visits the site for the first time, JS & CSS are put inline. The JS also has two more jobs: 1) Store JS & CSS into local storage; 2) Set cookie to flag that JS & CSS are in local storage.

When the browser access the site for the second time, server got the cookie and know that the browser already have related JS & CSS. So the render HTML has inline JS to read JS & CSS from local storage and insert into DOM tree.

This is basic idea how bing.com mobile version is created. You may need to put JS&CSS version control into consideration when implement it in production.

Thanks

6
  • Yes, pretty close to what I thinking of.
    – ajreal
    Sep 23, 2011 at 8:27
  • Google developed a module for Page Speed Mod that does the very same thing. Here's the page where they talk about the goods, bads and dontknows developers.google.com/speed/pagespeed/module/…
    – tacone
    Aug 1, 2015 at 0:59
  • upvoted, but wtf does "inline" mean in this case. "inline" has like 5 different meanings. Sep 4, 2015 at 8:06
  • 1
    It's actually increased to 10MB for Desktop and 5MB for mobile Jan 3, 2016 at 15:50
  • 1
    You don't need any cookie. you can simply read if the localstorage has the key/value you are looking for plus you must provide a version (for obvious invalidation purposes). This trick is only good after the second time the site is accessed and also if the assets are not in cache (for some reason)
    – vsync
    Dec 28, 2016 at 17:38
33

Doesn't the browser already do this for you, and probably better?

1
24

What's the point?

There is already a well established technique called client-side caching. What does HTML5 local storage brings in this case what caching is missing?

You may have some sort of strange application which must load chunks of JavaScript code dynamically so you can't effectively use the cache, but it's an extremely rare case.

Also, be aware of another thing. Browsers have specific policies for cache, and most browsers are quite good at managing cache well (removing only the older content, etc.). By implementing your home-made cache, you prevent the browsers from managing it correctly. Not only it can be criticized on its own, but it will also hurt you soon or later. Example: when the users of a web application are reporting bugs, often you answer by asking them to clear their cache. I'm not sure what you'll ask in your case, since clearing the cache will never resolve issues with your web app.


In response to your first edit (your second edit being off-topic):

I do aware browser cache, there will be still some header access checking

You seem to lack some understanding of browser caching. That's why it is essential to understand how it works first, before starting to implement your own home-made caching mechanism. Reinvent your own wheel only when you understand enough the existent wheels and have a good reason to not use them. See point 1 of my answer to the question "Reinventing the wheel and NOT regretting it".

When providing some data through HTTP, you can specify a few headers related to the cache:

  • Last-Modified specifies when the content was changed,
  • Expires specifies when the browser must ask to the server if the content changed.

Those two headers allow the browser to:

  • Avoid downloading the content again and again. If Last-Modified is set to the last month, and the content was already downloaded today a few hours before, there is no need to download it again.
  • Avoid querying for the date where the file was last modified. If Expires of a cache entity is May 5th, 2014, you don't have to issue any GET request neither in 2011, nor in 2012 or 2013, since you know that the cache is up-to-date.

The second one is essential for CDNs. When Google serves JQuery to a visitor of Stack Overflow or cdn.sstatic.net serves images or stylesheets used by Stack Overflow, they do not want browsers to query for a new version every time. Instead, they are serving those files once, set the expiration date to something long enough, and that's all.

Here's for example a screenshot of what's happening when I come to Stack Overflow home page:

A screenshot of Stack Overflow timeline in Chrome shows 15 files, 3 being requested, 12 being served from cache directly with no requests to remote servers

There are 15 files to serve. But where are all those 304 Not Modified responses? You only have three requests of content that changed. For everything else, the browser uses the cached version without making any request to any server.


To conclude, you really need to think twice before implementing your own cache mechanism, and especially find a good scenario where this can be useful. As I said at the beginning of my answer, I can find only one: where you are serving chunks of JavaScript to use them through, OMG, eval(). But in this case, I'm pretty sure that there are better approaches which are either:

  • More effective using the standard cache techniques, or
  • Easier to maintain.
4
  • +1 for this one. It is absolutely pointless. Almost in all cases absolutely. Caching by some unique, hash-based key is way better.
    – shabunc
    Sep 16, 2011 at 9:22
  • 1
    You are not entirely right about the browser cache. A hard refresh will by pass all the browser cache checking.
    – ajreal
    Sep 23, 2011 at 8:23
  • 1
    The link to reinventing the wheel and not regretting it is dead :'(
    – Esailija
    Jan 28, 2012 at 8:52
  • 4
    Bowser caching is not as straight forward as you may think, nor is it consistent across all browsers. For example, some browsers randomly decide to load web fonts (regardless of headers - can't find the article about this right now but I think it was Dave Rupert who discovered this). Also, ETAGs force browsers to check if a resource has been updated... and sometimes you can't remove ETAG (eg. Amazon S3) - so if your CSS file sends an ETAG header, it will always be checked for updates (304s are still a payload). In order to prevent unnecessary requests, custom caching is required. Nov 26, 2014 at 17:47
7

Client-side local caching should be way more optimized than using HTML5 local storage. Just make sure your javascript and CSS are in external cachable files and your page should load much quicker via browser cache than trying to extract them from local storage and execute them yourself.

Besides, the browser can start loading external resources as the page starts to load, before you can actually start running javascript in that page to then get your resources from HTML5 local storage.

Plus, you need code in the page anyway in order to load from HTML5 local storage, so just put all your JS in one external, cachable JS file.

5

Instead of reinventing the wheel just use the HTML5 offline functionality: http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html

2

You'll get much better performance by using a content delivery network (CDN) like Google's code library. Planned thoughtfully, the majority of your JS and CSS should be in every visitor's cache before they hit your site for the first time. Minify the remainder.

You can always benchmark browser caching vs your hand-rolled HTML5 solution. But my bet is that the native caching is going to beat the pants off it.

2

Using localStorage is fast(er)! My test showed

  • Loading jQuery from CDN: Chrome 268ms, FireFox: 200ms
  • Loading jQuery from localStorage: Chrome 47ms, FireFox 14ms

I guess saving the HTTP request already brings a big speed advantage. Everybody here seems to be conviced of the opposite, so please prove me wrong.

If you want to test my results I crated a tiny library that caches scripts in localStorage. Check it out on Github https://github.com/webpgr/cached-webpgr.js or just copy it from the example below.

The complete library:

function _cacheScript(c,d,e){var a=new XMLHttpRequest;a.onreadystatechange=function(){4==a.readyState&&(200==a.status?localStorage.setItem(c,JSON.stringify({content:a.responseText,version:d})):console.warn("error loading "+e))};a.open("GET",e,!0);a.send()}function _loadScript(c,d,e,a){var b=document.createElement("script");b.readyState?b.onreadystatechange=function(){if("loaded"==b.readyState||"complete"==b.readyState)b.onreadystatechange=null,_cacheScript(d,e,c),a&&a()}:b.onload=function(){_cacheScript(d,e,c);a&&a()};b.setAttribute("src",c);document.getElementsByTagName("head")[0].appendChild(b)}function _injectScript(c,d,e,a){var b=document.createElement("script");b.type="text/javascript";c=JSON.parse(c);var f=document.createTextNode(c.content);b.appendChild(f);document.getElementsByTagName("head")[0].appendChild(b);c.version!=e&&localStorage.removeItem(d);a&&a()}function requireScript(c,d,e,a){var b=localStorage.getItem(c);null==b?_loadScript(e,c,d,a):_injectScript(b,c,d,a)};

Calling the library

requireScript('jquery', '1.11.2', 'http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js', function(){
    requireScript('examplejs', '0.0.3', 'example.js');
});
3
  • 3
    Your measures are irrelevant. (1) If the user is new to the website, he has no jQuery in local storage anyway. (2) If, on the other hand, the user already visited your website, he has jQuery in cache, which means that it won't be loaded from CDN. This also leads to a third point: (3) local storage is proper to a given site, while jQuery on Google's CDN is shared by many sites, which means that a user who visited, say, Stack Overflow but is new to your site won't need to reload jQuery from CDN if you use the same version of jQuery. Mar 8, 2015 at 16:23
  • @MainMa Maybe this measure is not good, I see that now, but for the browser cache to work there needs to be a request send to a server which then returns a 304. This request takes more time than directly getting the file form the localstorage. Correct me if I'm wrong.
    – select
    Sep 7, 2015 at 14:51
  • @MainMa please also check the comments from programmers.stackexchange.com/a/105526/195684 there are more issues with the cache, like the ETAG comparison that make this custom caching faster
    – select
    Sep 7, 2015 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.