Saturday, June 02, 2007

Speeding up loading time by using Google Gears' LocalServer module

When I visited the Google Gear's developer site and read about the LocalServer module, the first thing that popped into my head was that it could be useful for speeding up our web applications.

I think the web application I am developing right now isn't ready to become an offline web app at least not yet. But when I read the following statement from the Google Gear developer site, I knew instantly that we can indeed use it to help speed up loading time and to acquire slightly better level of control over the user experience when using the web application.

***
The LocalServer always serves a cached resource when the conditions are met, regardless of the network connection. The URLs contained in a store are eligible for local serving without requiring the application to open the store.
***

This basically means that the Google Gear Local Server, using the ManagedResourceStore
  • intercepts all HTTP/HTTPS requests to a resource (be it an image, style sheet or javascript file),
  • checks if it is a captured resource and
  • serve the resource file from the LocalServer if it is found to be a captured resource,
and it does this whether the user's computer can access the server or not.

It can be akin to a local proxy server that caches resource files. The difference is that the store resides on the user's PC and not on a separate machine and our web application has control over the cached resources thru a couple of lines of javascript and a manifests file.

The manifests file has a JSON data structure with the list of resources to cache in the LocalServer and a version string. This version string is used to determine if the resources in the LocalServer should be updated.

{
"betaManifestVersion": 1,
"version": "6",
"entries": [
{ "url": "/resources/ajaxhelper/gears/gears_init.js"},
{ "url": "/resources/acs-subsite/core.js"},
{ "url": "/resources/ajaxhelper/yui-ext/yui-ext.js"},
{ "url": "/resources/ajaxhelper/ext/adapter/yui/ext-yui-adapter.js"},
{ "url": "/resources/ajaxhelper/ext/ext-all.js"},
{ "url": "/resources/ajaxhelper/ext/ext2-all.js"},
{ "url": "/resources/acs-templating/ajax-list.js"),
{ "url": "/resources/ajaxhelper/ext/resources/css/ext-all.css"},
{ "url": "/resources/ajaxhelper/ext/resources/css/ytheme-green.css"},
{ "url": "/resources/capital-projects/controlpanel/cp.css"},
{ "url": "/resources/jobs-db/controlpanel/cp.css"},
{ "url": "/resources/acs-templating/lists.css"},
{ "url": "/resources/style.css"},
{ "url": "/resources/acs-subsite/old-ui-master.css"}
]
}

contents of a sample manifests file

The lines of javascript will be responsible for
  • capturing the resource files into the LocalServer
  • checking for updates
  • updating the captured resource files
Notice that javascript is not needed to tell the browser to use the LocalServer each time a page is loaded, this is done automatically for you by Google Gears without using any additional javasript aside from the first one that instantiates the store and captures the resuource files.



<script src="/resources/ajaxhelper/gears/gears_init.js"></script>
<script>
if (!window.google || !google.gears) {
// console.log("google gears not installed");
} else {
// console.log("installed");

// initialize some variables
var STORE_NAME="csm_store"
var MANIFEST_FILENAME="csm-gears_manifest.json"

// instantiate google gears
try {
var localServer = google.gears.factory.create("beta.localserver","1.0");
} catch(e) {
// user denied access to google gears
}
if (typeof(localServer) == "object") {
var store = localServer.createManagedStore(STORE_NAME);
store.manifestUrl = "/"+MANIFEST_FILENAME;

// check for changes and capture files
store.checkForUpdate();

// notification for debugging only
/*
var timerId = window.setInterval(function() {
// When the currentVersion property has a value, all of the resources
// listed in the manifest file for that version are captured. There is
// an open bug to surface this state change as an event.
if (store.currentVersion) {
window.clearInterval(timerId);
console.log("Using store version: " +store.currentVersion);
} else if (store.updateStatus == 3) {
console.log("Error: " + store.lastErrorMessage);
}
}, 500);
*/
}
}
</script>


The above script, which is partially lifted from this tutorial, is placed on the landing page of the web site or web application. It loads up the entries from the manifest file into the LocalServer.

This is done only after checking that Google Gears is installed and will not need to be done again until any of the files in the manifest entries change, at which time changing the version string in the manifest file, and rerunning the javascript above will force Google Gears to recapture the files into the local store.

The script also tries to be unobtrusive. It doesn't alert the user that it's trying to use Google Gears and fails gracefully if it isn't installed.

If Google Gears is installed, the user will need to give explicit permission to the page for it to be able to use Google Gears.

gears-security

Although this is an interesting idea, I have yet to do benchmarks to determine how much of a speed improvement can be derived from this. As far as my preliminary testing goes I seem to get perceivably faster response times if the bigger javascript and css files are cached in the LocalServer.