Friday, October 14, 2011

Caching Javascript in a Mobile Web app

Earlier this week I promised I'd post a useful technique to reference, pre-fetch, and cache Javascripts, as a follow up to my review of an article on HTMLRocks describing HTML5 techniques for optimizing mobile Web performance.

So, here it goes.

The HTML5Rocks article showed how to follow all the links in a page and pre-fetch and cache their target pages in local storage. That was a good starting point, but for a mobile Web app to really work well offline you also need to fetch and cache the referenced JavaScripts, CSS, and images.

Here's how I do that in my apps.

I place the following utility Javascript at the top of my page under the <head> element:
<script type="text/javascript";gt;
window.appcache = {};

// Get a resource
window.appcache.get = function(url) {
  var doc = localStorage.getItem(url);
  if (doc != null)
    return doc;
  var http = new XMLHttpRequest();
  http.open("GET", url, false);
  http.send(null);
  if (http.status != 200)
    return null;
  localStorage.setItem(url, http.responseText);
  return http.responseText;
}

// Load a script
window.appcache.script = function(url, parent) {
  var e = document.createElement('script');
  e.type = 'text/javascript';
  e.text = window.appcache.get(url);
  parent.appendChild(e);
}
</script>


I'm not showing the error handling code here to keep it short, but you get the picture. The get(url) function downloads a resource and caches it, and the script(url, parent) function gets a resource and creates a script element with it.

Then to reference a Javascript script later in my page, instead of writing the usual:
<script type="text/javascript" src="foo.js"></script>

I write this:
<script type="text/javascript">
window.appcache.script('foo.js', document.head);
</script>


If you're loading pages in an <iframe> nested inside a main page as suggested in the HTML5Rocks article, you don't need to repeat the utility script in all your pages. Just have it once in the main page, then in the nested pages just write:
<script type="text/javascript">
window.parent.appcache.script('foo.js', document.head);
</script>


Or just set the appcache property on your <iframe> like this:
var nested = document.createElement('iframe');
nested.contentWindow.appcache = window.appcache;


Then you can write the same code everywhere:
<script type="text/javascript">
window.appcache.script('foo.js', document.head);
</script>


Hope this helps.

To the folks who've pinged me several times this week asking for this tip: Sorry for the delay but I've been kinda busy... I'll show how to fetch and cache CSS (similar to Javascripts) and images (using a data: url and base64-encoded image content) in the next few posts, probably this weekend.

1 comment:

Website design London said...

Nice java script code. Thanks for post. It is useful for me..


The postings on this site are my own and don’t necessarily represent positions, strategies or opinions of my employer IBM.