Some time ago there was a post on YUIBlog highlighting the findings of Wayne Shea and Tenni Theurer on the caching behavior of the iPhone. Curious if things have changed several iPhone OS updates later, I ran some experiments with OS3 and OS3.1.
- iPhone will not cache components bigger than 15K (was 25K in the previous experiment)
- total cache is about 1.5MB (was 500K)
- short-term memory cache will store components up to 1941K provided the component size does not divide by 4
- powering off the device still clears all the cache, Expires headers still important
- not sure since when, but closing all tabs clears the cache too
- consider HTML5 application cache to improve cacheability and provide offline experience – components in the application cache can be bigger than 15K and stay cached even after you clear Safari's cache from the Settings app (or clear it any other way)
15 is the new 25
So minification can definitely help you here. Minification may not be as beneficial as gzipping in desktop browsers, but it may be the difference between a cache hit or miss in the iPhone. Minify, then gzip. And, in general, try to keep your component sizes low - that always helps in any browser.
Total cache size
First off, how was the experiment run? I simply tailed the access log of a server, in order to monitor which components get requested:
$ tail -f ~/logs/http/access.log | grep "XXX.YYY.ZZZ.000"
Where XXX.YYY.ZZZ.000 is the IP address. You can also replace that with just "iPhone" if you think no one else is hitting this site with an iPhone.
Then I requested components with different sizes and look at what the log tail says.
Once it was clear that 15K is the maximum components size, the next question was how many of those 15K components can be cached before iPhone runs out of space allocated for caching? And the result was 105. Attempting to cache one more file resulted in removing existing ones from the cache. Then playing with the size of the very last component helped nail the exact number of bytes available in the cache – 105 * 15 + 7 = 1582K.
So the total cache is just a little over 1.5 MB (earlier research showed 0.5MB for earlier iPhone OS). Have in mind that this is the total cache shared between all pages, it's not per domain or per tab.
The iPhone has a little bit more cache space in the form of memory cache. The memory cache has no per-component size limit, so your components can be as big as the memory cache – 1941 bytes (don't ask how many attempts it took to nail this number).
So components under 15K go to the disk cache, a 16K component is never cached (so is 20, 24, …, 36,.. 100,… 1024 and so on), 17K and up (up to almost 2 megs) components are cached in memory.
This memory cache is very unreliable as you can guess, because it gets cleared very often, it's probably useful only in the same user session on your web site.
- Closing all tabs, except for blank ones (as when you do "New Page") and then closing Safari is the same as clearing the cache from Settings. So it's a good idea in your normal daily use to leave at least one page open, before you close Safari in order not to cause the implicit cache clearing.
- Tapping the reload icon in the address bar sends unconditional requests for all components, without the If-Modified-Since header and ignoring the Expires header. So to speed up your browsing, refresh the page by tapping the address bar and then tapping GO, don't use the refresh icon.
- The tests I ran were using OS 3.0 and OS 3.1.2. I got my phone last Christmas which means that according to this page it came with OS 2.2. I don't remember if I ran any tests with OS2.2. too. I do remember though that I tried some tests back when I didn't have a phone and asked help from Ryan Grove and Nicole Sullivan. Chatting over IM they were loading pages while I was tail-ing the server log. Those tests must have been with OS 2 or OS2.1. Back then the results showed that the limit for a component that gets stored in the cache was 10Meg, which was also the total size of the cache. Now I have my doubts that back then we only tested memory cache, not disk cache. In any event, it's important to note that those restrictions are all software restrictions. No matter what model the phone, it's the OS that sets the limits. Different models with the same OS will behave the same when it comes to caching sizes.
HTML5 offline application cache
All in all we can safely summarize that the iPhone has no cache to speak of. 15K per component is nothing and the limit of 1.5Megs shared with all other pages will have your cached components kicked out pretty quickly.
So – what's an iPhone performance optimizer to do? Use HTML5 goodies.
Another thing to do is use the offline application cache. It's meant to support applications to work offline, but it also ends up being useful to improve caching of online applications as well.
What you need is a simple text file called a manifest. In there you list all the components required by your application. E.g.
CACHE MANIFEST /root/path/to/images/image.jpg or/maybe/relative/paths/too/scripts.js http://example.org/good-old/absolute/path/oojs-home.jpg
It's important to serve this file with content type
Then in your
html tag just point to that file. Let's say you called the manifest
mycache.manifest (could be dynamic, php, or anything, as long as it's served with the proper content type). So your HTML should start like the following:
<!DOCTYPE html> <html manifest="mycache.manifest">
Now the browser will request the manifest file every time (Expires header won't help you here) and if its contents is changed it will quietly and unobtrusively download the updated components in the background and the next time the user will see the updated page. Needless to say it makes sense that all the pages of the site share the same manifest.
The best part is that when using offline cache none of the restrictions mentioned above apply – you can store files bigger than 15K and you don't share your total cache space with anyone.
I used this for a personal project – whomsy.com if you want to play with some requests and monitor the traffic (e.g. using the iPhone simulator and Charles proxy).
Manifest – not just for iPhone?
- Browser support – currently Webkit browsers support manifests, and IE doesn't. Firefox does support offline cache, however it shows an ugly confirmation message at the top of the page and you normally don't want to stress out your users with warning messages (see screenshot below)
- The "homepage" meaning the page that includes the cache manifest also gets cached implicitly. This could be undesired behavior for many sites, but could work just fine for Ajaxy one-page-sites and applications.
Overall, I'm pretty enthusiastic about using offline cache for the purposes of normal page caching too. The future is here, it's just not evenly distributed (nor supported in IE) yet 🙂