How to Use HTML5 Local Storage

localstorage

CraigBuckler

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:

  1. You want to increase performance by caching data in the browser so it can be retrieved without additional server requests.
  2. 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.
  3. You want your application to work offline without a live internet connection.

Until recently, there were three primary options…

JavaScript Variables

The simplest choice is JavaScript variables. For example, you could create a global dataStore object and assign values to it, e.g.

//global dataStore object
var dataStore = {};
// set a value
dataStore.myvalue = “Hello World!”;
// retrieve values in any function
function doSomething() {
console.log( dataStore.myvalue );
}
doSomething();

You can also store values in the page DOM as node attributes or properties, e.g.

<!– html node –>
<div id=”mywidget”></div>
<script>
// store data in node
var mywidget = document.getElementById(“mywidget”);
mywidget.setAttribute(“data-myvalue”, “Hello World!”);
// retrieve values in any function
function doSomething() {
mywidget.textContent = mywidget.getAttribute(“data-myvalue”);
}
doSomething();
</script>

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

Cookies are chunks of textual data. Cookie handling is a little clunky in JavaScript; the document.cookie value is a basic text string which must be parsed, e.g.

// cookie handling function
var Cookie = function() {
// set a cookie name, value and expiry in seconds
function Set(name, value, secs) {
var expires = “”;
if (secs) {
var date = new Date();
date.setTime(date.getTime() + (secs * 1000));
expires = “; expires=”+date.toUTCString();
}
document.cookie = name + “=” + String(value) + expires + “; path=/”;
}
// get a cookie by name
function Get(name) {
var
cookies = document.cookie.split(“;”),
value = null,
regexp = new RegExp(“^\s*” + name + “=(.*)$”);
for (var c = 0; c < cookies.length && !value; c++) {
var match = cookies[c].match(regexp);
if (match.length == 2) value = match[1];
}
return value;
}
// public methods
return {
Set: Set,
Get: Get
};
}();
Cookie.Set(“myvalue”, “Hello World!”);
console.log( Cookie.Get(“myvalue”) );

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.
  • Even if you only want to store 50KB of information, cookie data is sent with every HTTP request and returned with the response. It’s appended to every HTML page, image, CSS file, JavaScript file, Ajax call etc. To put this into context, if you had ten 1KB images on your page, 50KB of cookie data would equate to one megabyte of additional network traffic. That would certainly be noticeable on slow or mobile connections.

window.name

The browser window.name property is slightly unusual. You can set and retrieve a single string value, e.g.

window.name = “Hello World!”;
console.log( window.name );

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.

localStorage

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.

sessionStorage

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

Libraries such a Modernizr can verify you have Web Storage support. Alternatively, you can check using plain JavaScript:

var LSsupport = !(typeof window.localStorage == ‘undefined’);
var SSsupport = !(typeof window.sessionStorage == ‘undefined’);
if (LSsupport && SSsupport) {
console.log( “localStorage and sessionStorage are available” );
}

Storing and Retrieving Values

There are a number of ways to store values:

// setItem method
localStorage.setItem( “name”, “value” );
// property method
localStorage.name = “value”;
// associate array-like method
localStorage[“name”] = “value”;

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:

// getItem method
console.log( localStorage.getItem( “name” ) );
// property method
console.log( localStorage.name );
// associate array-like method
console.log( localStorage[“name”] );

Storing Objects

Storing complex values such as objects requires data serialization. We can achieve this using the JSON.stringify() and JSON.parse() methods, e.g.

// define object
var obj = {
“item1”: “value1”,
“array1”: [1, 2, 3]
};
// store object
localStorage.setItem( “obj”, JSON.stringify( obj ) );
// retrieve object
console.log( JSON.parse( localStorage.getItem( “obj” ) ) );

Deleting Stored Values

Previously stored values can be deleted using removeItem():

// getItem method
localStorage.removeItem( “name” );

Alternatively, we can use the delete statement:

// property method
delete localStorage.name;
// or
delete localStorage[“name”];

The whole data store can be deleted using the clear() method:

// remove all data
localStorage.clear();

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:

for (var i = 0; i < localStorage.length; i++) {
var name = localStorage.key( i );
var value = localStorage.getItem( name );
console.log( name + ” is set to ” + value );
}

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)

Example:

window.addEventListener(“storage”, function(e) {
var msg =
e.key + ” was changed in page ” + e.url +
” from ” + e.oldValue + ” to ” + e.new;
console.log( msg );
});

Defensive Development

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:

try {
localStorage.setItem( “name”, aBigValue );
}
catch(e) {
console.log( “Storage failed” );
}

HTML5 Web Storage is easy to use and has many practical uses. Further tutorials about local storage, cookies, offline applications and the page history API are contained within my Learning JavaScript Programming video course.

 

To view the additional courses that Craig has done for Infinite Skills, click the titles below:

CSS3 Transformations and Animations

Learning JavaScript Programming

Learning jQuery Programming

Comments

comments

Save $50 when you sign up for an annual Learning Library account Learn More