Web Storage has quickly become one of the most popular HTML5-related additions to the web developer toolkit. More specifically,
localStorage has found a home in the hearts and minds of web developers everywhere, providing very quick and easy client-side data storage that persists across sessions. With a simple key-value interface, we’ve seen sites take advantage of
localStorage in unique and interesting ways:
- Disqus, the popular feedback management system, uses
localStorageto save your comment as you type. So if something horrible happens, you can fire back up the browser and pick up where you left off.
localStorageto improve their mobile site performance (more info).
Of the use cases I’ve seen, the Google/Bing approach is one that seems to be gaining in popularity. This is partly due to the difficulties of working with the HTML5 application cache and partly due to the publicity that this technique has gained from the work of Steve Souders and others. Indeed, the more I talk to people about
localStorage and how useful it can be for storing UI-related information, the more people I find who have already started to experiment with this technique.
What I find intriguing about this use of
localStorage is that there’s a built-in, and yet unstated, assumption: that reading from
localStorage is an inexpensive operation. I had heard anecdotally from other developers about strange performance issues, and so I set out to quantify the performance characteristics of
localStorage, to determine the actual cost of reading data.
Not too long ago, I created and shared a simple benchmark that measured reading a value from
localStorage against reading a value from an object property. Several others tweaked the benchmark to arrive at a more reliable version. The end result: reading from
localStorage is orders of magnitude slower in every browser than reading the same data from an object property. Exactly how much slower? Take a look at the following chart (higher numbers are better).
You may be confused after looking at this chart because it appears that reading from
localStorage isn’t represented. In fact, it is represented, you just can’t see it because the numbers are so low as to not even be visible with this scale. With the exception of Safari 5, whose
localStorage readings actually show up, every other browser has such a large difference that there’s no way to see it on this chart. When I adjust the Y-axis values, you can now see how the measurements stack up across browsers:
By changing the scale of the Y-axis, you’re now able to see a true comparison of
localStorage< versus object property reads. But still, the difference between the two is so vast that it's almost comical. Why?
What's Going On?
In order to persist across browser sessions, values in
localStorage are written to disk. That means when you're reading a value from
localStorage, you're actually reading some bytes from the hard drive. Reading from and writing to a hard drive are expensive operations, especially as compared reading from and writing to memory. In essence, that's exactly what my benchmark was testing: the speed of reading a value from memory (object property) compared to reading a value from disk (
Making matters more interesting is the fact that
localStorage data is stored per-origin, which means that it's possible for two or more tabs in a browser to be accessing the same
localStorage data at the same time. This is a big pain for browser implementors who need to figure out how to synchronize access across tabs. When you attempt to read from
localStorage, the browser needs to stop and see if any other tab is accessing the same area first. If so, it must wait until the access is finished before the value can be read.
So the delay associated with reading from
localStorage is variable - it depends a lot on what else is going on with the browser at that point in time.
Given that there is a cost to reading from
localStorage, how does that affect how you would use it? Before coming to a conclusion, I ran another benchmark to determine the effect of reading different size pieces of data from
localStorage. The benchmarks saves four different size strings, 100 characters, 500 characters, 1000 characters, and 2000 characters, into
localStorage and then reads them out. The results were a little surprising: across all browsers, the amount of data being read did not affect how quickly the read happened.
I ran the test multiple times and implored my Twitter followers to get more information. To be certain, there were definitely a few variances across browsers, but none that were large enough that it really makes a difference. My conclusion: it doesn't matter how much data you read from a single
I followed up with another benchmark to test my new conclusion that it's better to do as few reads as possible. The results correlated with the earlier benchmark in
that reading 100 characters 10 times was around 90% slower across most browsers than reading 10000 characters one time.
Given that, the best strategy for reading data from
localStorage is to use as few keys as possible to store as much data as possible. Since it takes the roughly same amount of time to read 10 characters as it does to read 2000 characters, try to put as much data as possible into a single value. You're getting hit each time you call
getItem() (or read from a
localStorage property), so make sure that you're getting the most out of the expense. The faster you get data into memory, either a variable or an object property, the faster all subsequent actions.