Storing information locally on a user’s computer is a powerful strategy for a developer who is creating something for the Web. In this article, we’ll look at how easy it is to store information on a computer to read later and explain what you can use that for.
[Offtopic: by the way, did you already get your copy of the Smashing Book?]
Adding State To The Web: The “Why†Of Local Storage
The main problem with HTTP as the main transport layer of the Web is that it is stateless. This means that when you use an application and then close it, its state will be reset the next time you open it. If you close an application on your desktop and re-open it, its most recent state is restored.
This is why, as a developer, you need to store the state of your interface somewhere. Normally, this is done server-side, and you would check the user name to know which state to revert to. But what if you don’t want to force people to sign up?
This is where local storage comes in. You would keep a key on the user’s computer and read it out when the user returns.
C Is For Cookie. Is That Good Enough For Me?
The classic way to do this is by using a cookie. A cookie is a text file hosted on the user’s computer and connected to the domain that your website runs on. You can store information in them, read them out and delete them. Cookies have a few limitations though:
- They add to the load of every document accessed on the domain.
- They allow up to only 4 KB of data storage.
- Because cookies have been used to spy on people’s surfing behavior, security-conscious people and companies turn them off or request to be asked every time whether a cookie should be set.
To work around the issue of local storage — with cookies being a rather dated solution to the problem — the WHATWG and W3C came up with a few local storage specs, which were originally a part of HTML5 but then put aside because HTML5 was already big enough.
Using Local Storage In HTML5-Capable Browsers
Using local storage in modern browsers is ridiculously easy. All you have to do is modify the localStorage
object in JavaScript. You can do that directly or (and this is probably cleaner) use the setItem()
and getItem()
method:
localStorage.setItem('favoriteflavor','vanilla');
If you read out the favoriteflavor
key, you will get back “vanillaâ€:
var taste = localStorage.getItem('favoriteflavor'); // -> "vanilla"
To remove the item, you can use — can you guess? — the removeItem()
method:
localStorage.removeItem('favoriteflavor'); var taste = localStorage.getItem('favoriteflavor'); // -> null
That’s it! You can also use sessionStorage
instead of localStorage
if you want the data to be maintained only until the browser window closes.
Working Around The “Strings Only†Issue
One annoying shortcoming of local storage is that you can only store strings in the different keys. This means that when you have an object, it will not be stored the right way.
You can see this when you try the following code:
var car = {}; car.wheels = 4; car.doors = 2; car.sound = 'vroom'; car.name = 'Lightning McQueen'; console.log( car ); localStorage.setItem( 'car', car ); console.log( localStorage.getItem( 'car' ) );
Trying this out in the console shows that the data is stored as [object Object]
and not the real object information:
You can work around this by using the native JSON.stringify()
and JSON.parse()
methods:
var car = {}; car.wheels = 4; car.doors = 2; car.sound = 'vroom'; car.name = 'Lightning McQueen'; console.log( car ); localStorage.setItem( 'car', JSON.stringify(car) ); console.log( JSON.parse( localStorage.getItem( 'car' ) ) );
Where To Find Local Storage Data And How To Remove It
During development, you might sometimes get stuck and wonder what is going on. Of course, you can always access the data using the right methods, but sometimes you just want to clear the plate. In Opera, you can do this by going to Preferences → Advanced → Storage, where you will see which domains have local data and how much:
Doing this in Chrome is a bit more problematic, which is why we made a screencast:
Mozilla has no menu access so far, but will in future. For now, you can go to the Firebug console and delete storage manually easily enough.
So, that’s how you use local storage. But what can you use it for?
Use Case #1: Local Storage Of Web Service Data
One of the first uses for local storage that I discovered was caching data from the Web when it takes a long time to get it. My World Info entry for the Event Apart 10K challenge shows what I mean by that.
When you call the demo the first time, you have to wait up to 20 seconds to load the names and geographical locations of all the countries in the world from the Yahoo GeoPlanet Web service. If you call the demo a second time, there is no waiting whatsoever because — you guessed it — I’ve cached it on your computer using local storage.
The following code (which uses jQuery) provides the main functionality for this. If local storage is supported and there is a key called thewholefrigginworld
, then call the render()
method, which displays the information. Otherwise, show a loading message and make the call to the Geo API using getJSON()
. Once the data has loaded, store it in thewholefrigginworld
and call render()
with the same data:
if(localStorage && localStorage.getItem('thewholefrigginworld')){ render(JSON.parse(localStorage.getItem('thewholefrigginworld'))); } else { $('#list').html(''+loading+' '); var query = 'select centroid,woeid,name,boundingBox'+ ' from geo.places.children(0)'+ ' where parent_woeid=1 and placetype="country"'+ ' | sort(field="name")'; var YQL = 'http://query.yahooapis.com/v1/public/yql?q='+ encodeURIComponent(query)+'&diagnostics=false&format=json'; $.getJSON(YQL,function(data){ if(localStorage){ localStorage.setItem('thewholefrigginworld',JSON.stringify(data)); } render(data); }); }
You can see the difference in loading times in the following screencast:
The code for the world info is available on GitHub.
This can be extremely powerful. If a Web service allows you only a certain number of calls per hour but the data doesn’t change all that often, you could store the information in local storage and thus keep users from using up your quota. A photo badge, for example, could pull new images every six hours, rather than every minute.
This is very common when using Web services server-side. Local caching keeps you from being banned from services, and it also means that when a call to the API fails for some reason, you will still have information to display.
getJSON()
in jQuery is especially egregious in accessing services and breaking their cache, as explained in this blog post from the YQL team. Because the request to the service using getJSON()
creates a unique URL every time, the service does not deliver its cached version but rather fully accesses the system and databases every time you read data from it. This is not efficient, which is why you should cache locally and use ajax()
instead.
Use Case #2: Maintaining The State Of An Interface The Simple Way
Another use case is to store the state of interfaces. This could be as crude as storing the entire HTML or as clever as maintaining an object with the state of all of your widgets. One instance where I am using local storage to cache the HTML of an interface is the Yahoo Firehose research interface (source on GitHub):
The code is very simple — using YUI3 and a test for local storage around the local storage call:
YUI().use('node', function(Y) { if(('localStorage' in window) && window['localStorage'] !== null){ var key = 'lastyahoofirehose'; localStorage.setItem(key,Y.one('form').get('innerHTML')); if(key in localStorage){ Y.one('#mainform').set('innerHTML',localStorage.getItem(key)); Y.one('#hd').append('Notice: We restored your last search for you - not live data'); } } });
You don’t need YUI at all; it only makes it easier. The logic to generically cache interfaces in local storage is always the same: check if a “Submit†button has been activated (in PHP, Python, Ruby or whatever) and, if so, store the innerHTML
of the entire form; otherwise, just read from local storage and override the innerHTML
of the form.
The Dark Side Of Local Storage
Of course, any powerful technology comes with the danger of people abusing it for darker purposes. Samy, the man behind the “Samy is my hero†MySpace worm, recently released a rather scary demo called Evercookie, which shows how to exploit all kind of techniques, including local storage, to store information of a user on their computer even when cookies are turned off. This code could be used in all kinds of ways, and to date there is no way around it.
Research like this shows that we need to look at HTML5′s features and add-ons from a security perspective very soon to make sure that people can’t record user actions and information without the user’s knowledge. An opt-in for local storage, much like you have to opt in to share your geographic location, might be in order; but from a UX perspective this is considered clunky and intrusive. Got any good ideas?
(al)
© Christian Heilmann for Smashing Magazine, 2010. | Permalink | Post a comment | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: Coding, localstorage, performance, programming, security