Sunday, 19 June 2011
HTML5’s AppCache mechanism is one confused little puppy. Purporting to be for taking web applications offline — a compelling and useful thing — it’s more often used by performance-hungry sites that want to use it as an online cache.
Unfortunately, this means that those sites will be popping up dialogues like this:
Even more unfortunately, if you click “Don’t Allow”, you’ll just be asked to approve it again next time you navigate to the site.
And again. And again.
I’ve heard lots of developers complain about AppCache, and I suspect it’s because, in the words of Marlo, they want it to be one way, but it’s the other way.
Making AppCache Cache Apps
For AppCache to do what it purports to do, it needs to be initiated by the user, rather than by the site. The trigger for getting some extra disk space and special treatment should be user interaction (roughly, a “take this application offline” or “add to my app gallery” button), along with some metadata about what that means (the manifest, etc.). Having random Web sites pop up modal dialogues simultaneously sucks and blows.
That implies that offline apps need some special status; something like Chrome’s “apps” listing, or an icon on a launch screen, but without the need to list it in a browser-specific “store” (a repulsive grab for control of the Web, a la Apple’s AppStore, if I ever saw one). You should be able to install from any Web site, not just one ordained by your browser vendor.
Making Browser Caches Cache the Web
That’s not going to happen until browser vendors supply a viable online cache for those performance junkies, so they don’t feel the need to abuse AppCache.
There are lots of things that need improvement in browser caches (in my experience, deploying a single-user local Squid has a HUGE performance impact, both because of better caching and better connection management, although perhaps Firefox 5 will address the latter).
However, for the purposes of this discussion, AppCache does two things that are attractive to your garden variety performance nut; it makes a dependable slice of space available, and it allows you to prefetch things into it.
Giving a site a guaranteed slice of the cache (called “cache pinning” in the old days of Web caching) is a bit tricker, but doable. I’d start by suggesting that bookmark/favourite’d sites get an automatic slice (say, 10M), while a site that’s been visited recently (i.e., one of the last N sites surfed) gets a smaller slice (say, 2M).
Then, give sites control over their preferentially-cached content by offering refined Cache-Control directives, so that (for example) a video on the site doesn’t blow the rest of the cache away.
This approach means that when your cache becomes too big, the least recent site is evicted, rather than the least recent resource. That gives sites a much more dependable behaviour; they’re either in-cache (to the degree determined by the cache bucket size) or not, governed by the user’s behaviour towards the site plus their own freshness policies. Contrast that with a straight LRU or even the relatively exotic Greedy Dual-Size; while these are great eviction algorithms for a shared cache, they don’t make as much sense for single-user caches.
That’s just a straw-man, of course. The important thing is that we need to start a dialogue about fixing browser caching, rather than abusing something not designed for it into the role. Who’s up for it?
I’ll note here that nowhere have I suggested that HTML5’s definition of AppCache needs changing (beyond, perhaps, some judicious UI advice); while I do think we could have defined it in a way that fix in better with Web caching better (especially that HTTP caching already supports disconnected operation), it’s too late for that, and we all have better things to do than get into religious wars about style. See Mike Kelly’s blog for an alternate view.
I also think that AppCache needs to be extended quite a bit to be really useful for offline (e.g., with fallback representations for failed interactions, queues for outgoing updates, etc.), but I can understand why HTML5 doesn’t want to go the whole hog in one go.