By: Craig Buckler
The more complex your web application, the greater your requirement to store data client-side in the web browser. There are several reasons why it may be practical:
- You want to increase performance by caching data in the browser so it can be retrieved without additional server requests.
- You have a significant quantity of data which is primarily required client-side during operation, e.g. HTML strings or configuration settings such as background colors or widget sizes.
- You want your application to work offline without a live internet connection.
Until recently, there were three primary options…
You can also store values in the page DOM as node attributes or properties, e.g.
This can be practical for retaining data specific to your widget, although it’s slower than using variables and far riskier – other code could overwrite the data or handle it in an unexpected way.
Local and DOM variables may be practical for single-page applications but they are not retained. Refresh the page or link elsewhere and they are lost forever.
Cookies can be assigned an expiry date which makes them persist beyond page refreshes, browser restarts and system reboots. Values for the domain are transmitted between the client and the server in the HTTP header so they remain the best method of retaining state, i.e. a user stays logged in to a web application between pages.
However, cookies have several limitations:
- All browsers provide cookie-blocking technologies. They were labelled as a serious threat to internet privacy and, while this is a little unfair, you may find users disable your safe cookies.
- Storage space is limited. Browsers differ, but you generally cannot store more than 20 cookies of 4KB each.
The browser window.name property is slightly unusual. You can set and retrieve a single string value, e.g.
Once you’ve set this value, you can refresh the page or link elsewhere but the window.name is retained. It works in every browser, no data is sent to the server and you can store several megabytes of information.
Again, there are a number of issues:
- The value is lost when the tab or browser is closed.
- If you navigate to another domain, the code can analyse and modify your values. It should not be used to store sensitive data.
- window.name was never designed to be used for storage. There’s no guarantee browser vendors will continue to support it.
HTML5 Storage Options
Local storage was one of the first issues tackled in HTML5. Vendors realised that web projects were becoming more sophisticated and client-heavy applications needed to store data.
One of the initial ideas was the Web SQL Database. This was an attempt to bring relational database technologies to the browser. While it is available in the Webkit/Blink browsers, it was never implemented in IE or Firefox. The W3C abandoned the specification in 2010 so it’s best avoided.
More recently, most vendors have added IndexedDB. This provides a structured, transactional, high-performance NoSQL-like data store with a synchronous and asynchronous API. IndexedDB is fairly new but is supported in IE10+, Firefox 23+, Chrome 28+ and Opera 16+. The downsides: IndexedDB is fairly complex and not available in older or mobile browsers.
Similarly, the File API is being adapted to permit writing as well as reading of data on the local file system. However, it remains a proposal and has limited support in Chrome only. While it could be suitable for large quantities of sequential text or binary data, it does not currently offer transactions, search or indexing facilities.
Fortunately, there is a simpler option: the Web Storage API. If you’re happy to use name/value pairs, the localStorage and sessionStorage APIs are a W3C Recommendation which have wide browser support including IE8+, iOS and Android.
window.localStorage retains data in the browser even when the user links elsewhere, closes the tab, restarts their browser or reboots the OS. Like cookies, Web Storage retains string values and is domain-specific, i.e. a page on domainx.com cannot read data stored by domainy.com. However, unlike cookies, values in localStorage do not expire, the data limit is far larger (generally 5MB), and information is not transferred to and from the server in every HTTP request.
When a page wants to store data, most browsers ask the user for permission. This data can also be cleared in the browser options.
Vendors have different approaches for storing the data. For example, IE uses an XML file while Firefox has a SQLite database. Note that, like cookies, anyone with direct access to the device can inspect stored values. In addition, values could be inspected by a third-party if your application has a cross-site scripting (XXS) vulnerability. While you could implement some form of encryption, it’s advisable to leave sensitive data on the server rather than store it on the client.
window.sessionStorage is identical to window.localStorage except that data is retained temporarily during the session and lost when the user closes the application tab or browser.
sessionStorage has an identical API to localStorage. The following examples use localStorage but they could be replaced with sessionStorage if you preferred.
How to Determine Whether a Browser Supports Web Storage
Storing and Retrieving Values
There are a number of ways to store values:
setItem() is the safest option since you can set any name and not clash with other localStorage properties or methods.
Similarly, there are three ways to retrieve values:
Storing complex values such as objects requires data serialization. We can achieve this using the JSON.stringify() and JSON.parse() methods, e.g.
Deleting Stored Values
Previously stored values can be deleted using removeItem():
Alternatively, we can use the delete statement:
The whole data store can be deleted using the clear() method:
Iterating Over Stored Data
The sessionStorage and localStorage length property returns the number of stored items. The .key() method returns the stored key name when passed a numeric index. We can therefore iterate over the whole data store:
Web Storage Events
When sessionStorage or localStorage values are modified, an event is fired to all other tabs/windows sharing the same data store. This can be useful when a user has your application open in two or more tabs and expects to see changes synchronised.
To listen for storage events, you must create a handler function for the “storage” event type. This is passed an event object with properties about the change:
- key – the data name
- newValue – the data value (this may be null if removeItem() or clear() were called)
- oldValue – the old data value before it was changed
- url – the address of the page which made the change
- storageArea – the storage object modified (localStorage or sessionStorage)
localStorage and sessionStorage cannot be guaranteed to work as you expect. The first problem is older browsers such as IE7; detecting whether storage is available may not be enough if you absolutely must store a value. Fortunately, a number of cross-browser shims (or polyfills) are available which implement Web Storage in older browsers by falling back to cookie or window.name methods. Refer to the Modernizr HTML5 Cross Browser Polyfills for downloads (https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#web-storage-localstorage-and-sessionstorage).
Even when Web Storage is available, the user can prevent your application from storing data or, in extreme cases, you may exceed the space permitted. To code around these issues, a try-catch block can test whether storage succeeds and react on failure:
To view the additional courses that Craig has done for Infinite Skills, click the titles below: