When the Web was young, our servers were powerful and our clients were weak so websites stored the vast majority of their data and logic on the server. But now we have increasingly more powerful clients, thanks in large part to the rapid innovation of mobile browsers and the advent of HTML5. As a result, websites are moving more of their data and logic to the client.
In this two-part series, I explain how to store data on the client using HTML5 APIs, and how client-side storage can improve both application performance and the user experience.
How We Got Here
To understand client-side storage today, it helps to look at the history of how we got to where we are now. In the first iteration of the Web, there was no way for websites to store data in the browser that would persist across browser sessions. It was possible to store state by using the query URL, like remembering a session ID (?sessionID=3213) and retrieving state from a database, but if users left a website or restarted their computer, the session information would be gone.
In 1994, a few engineers at Netscape were working on an e-commerce solution and needed a way to track the content of shopping cart baskets across browser sessions. They invented the concept of Web cookies (based on the computing concept of "magic cookies") and introduced them in the Mosaic Netscape browser later that year. Internet Explorer (IE) supported them the following year in IE2, and soon many websites started using them. They were most often used for user sessions, website personalization, ad tracking, and website analytics.
There was an increasing number of issues with cookies, however, especially as Web developers tried to use them in ways the creators didn't originally envision.
Cookies pose multiple security issues. They are unencrypted, so unless your entire website is delivered over SSL, the cookies aren't secure. As some hackers discovered, cookies can also be stolen via cross-site scripting techniques and DNS spoofing. When users found out about the security and privacy issues with cookies (thanks to mainstream news articles and US FTC hearings), many users started to restrict or entirely disable cookies meaning that websites could not always assume they could use cookies.
Cookies also pose performance issues. Because cookies are included in every HTTP request, they can affect how long it takes for a browser to download a webpage which means you don't want to store large amounts of data in them. And even if you wanted to store lots of data, you usually couldn't. Most browsers restricted each cookie to a max size of 4KB and allowed a max of 20 cookies per domain not a lot of space.
Web developers wanted a way to persistently store data in the client, and they weren't getting what they needed from cookies. A few clever developers came up with hacks for client-side storage, like using window.name or Flash local storage, but, well, you can only go so far with these hacks.
The HTML5 Storage APIs
Luckily, we are now in the era of "HTML5": the new set of HTML, CSS, and JavaScript specifications that try to make Web development easier and websites more powerful. These specifications include multiple approaches to client-side storage that go far beyond cookies: localStorage, IndexedDB, and the File API. Why multiple approaches? As we'll see, the APIs are quite different and so are their use cases.
localStorage
The localStorage API comes from the Web Storage specification, and it's the simplest of the APIs. It's a straighforward key/value store for string values that persists the data in the browser. That spec also includes sessionStorage, a way to store data for just a session, but it's not pertinent to this discussion because it's not as persistent. Both APIs expose the same set of methods for setting and getting items, plus events for finding out when items are added and removed.
In this example, I store a favorite fish in localStorage, retrieve and display the value, and then remove the value and check that it's gone.
localStorage.setItem('favoriteFish', 'tuna');
document.getElementById(‘fish’).innerHTML = “My favorite fish is: “ + localStorage.getItem('favoriteFish');
localStorage.removeItem('favoriteFish');
if (!localStorage.getItem('favoriteFish')) {
document.getElementById(‘fish’).innerHTML = “I don’t have a favorite fish anymore :( ”;
}


