html5-storage-cookies

HTML 5 Storage is better, but cookies aren’t gone yet

HTML 5 Storage is a promising addition to the web developers arsenal. However, it's name is confusing to many novices because it implies a connection with HTML markup itself. HTML 5 Storage may be part of the HTML 5 specification, but we don't use HTML tags to access it. Instead, we use JavaScript.

The idea of using JavaScript to access data may scare a few people off, especially those comfortable with and used to accessing cookies from a server-side language (PHP, ColdFusion, ASP, etc). Cookies are still the right choice for storing "user-browser-specific" data for use within server-side scripts. However, when the need arises to permanently store data, and retrieve it from JavaScript code, cookies present some issues; issues that have been solved in HTML 5 Storage.

The Good Stuff

  • Performance. When a cookie is stored, a request is sent to the web browser to store that cookie name/value within the browser itself. Then, with each page request after that, the cookie is sent to your web server, so it can be used by your server-side code.

    All cookies for a particular domain are sent with each page request. This is regardless of whether or not you actually need the cookie value. So, when your visitor loads a web page on your site, not only does their web browser need to request the page, it also needs to send along all of the cookies related to that site. In most cases, this is inefficient.

    HTML 5 Storage, on the other hand, does not transfer data at all, it stays within the browser, and is accessible "on-demand" by JavaScript. This all happens within the browser, the web server is never actually sent any data, and hence, there is no overhead with each page request.
     

  • Capacity. In a nutshell, you get more with HTML Storage. Cookies allow you, at a minimum, 4KB per cookie. The total number of cookies per domain varies greatly among browsers – but the RFC spec specifies that at least 20 cookies per domain be allowed.

    With HTML 5 Storage, you get at least 5MB per domain. In some browsers, you can request additional storage, subject to the user's acceptance. I have not found any evidence that there is a limitation on the number of keys (variables) used to store the data, or that the key names themselves consume data.
     

  • Security. Cookie data is transferred, via HTTP on the internet, between a user's web browser and the web server requesting the data. Whether you are transferring bags of cash from a bank vault to a secure location, or transferring data over a publicly available medium, it is open to attack.
    Browser cookies security

    HTML 5 Storage, on the other hand, is kept on the client-side. That is, it is transferred between your browser's internal database, and the client-side JavaScript code that requests it.

 

I said promising, not perfect

The points above might make you believe that HTML 5 Storage is a no-brainer. But, let's

  • JavaScript Only. HTML 5 Storage, despite it's deceiving name, can be accessed only via JavaScript. So, although a visitor's browser may well support HTML 5, it may have JavaScript disabled, hence disabling access to the HTML 5 Storage data.

    That being said, don't use HTML 5 Storage for things like pre-filling form fields, user preferences, shopping carts, etc. These are best managed with server-side storage.
     

  • Browser-specific. This disadvantage is shared by cookies. HTML 5 Storage is within the web browser, so a user who likes to switch browsers or PCs from time-to-time will not have a consistent experience.
     
  • No expiration date. Unlike cookies, HTML 5 Storage does not offer a way to specify an expiration date on data. For this reason, they are not ideal for storing "mortal" data such as shopping carts.
     
  • Difficult server-side access. Cookies are in the browser, so they are accessible via JavaScript. But, they're also sent to the web server with each request, so your server-side code has access to them.  HTML 5 Storage data, however, is directly available only to the client-side (JavaScript). Now, I say difficult for a reason, because it's not impossible to access client-side only data from a server-side script. JavaScript allows us to call server-side scripts via AJAX, and in doing so, we can pass parameters to those scripts. Those parameters could be HTML 5 Storage values if need be.

 

Hey browser, do you have what it takes?

Before we get too excited and start writing code that's heavily dependent on HTML 5 Storage, we want to be sure that the user's browser supports it. JavaScript makes easy work of this, by using the built-in typeof keyword:

if(typeof Storage !== 'undefined') {
	// use HTML 5 Storage
}
else {
	// use good 'ol cookies
}

I've seen code lurking around that checks for browser versions, instead of directly checking for the existence of the Storage object as shown above.

if ($.browser.msie && $.browser.version <= 7) {
     // use cookies
}
else {
     // use HTML 5 storage
}

This is a bad practice, it introduces too many variables into your code, and makes too many predictions about future web browser capabilities.

 

But my thing ain't a string

The one area that HTML 5 Storage didn't break any new ground in is the type of data that can be stored. We're still stuck with string data. So, what happens when we want to store an object that's not a string?

Enter JavaScript Object Notation, or JSON. JSON sounds a lot fancier than it is. It's really just a way to convert, or serialize, an object to a string; in our case, a string that can be stored in an HTML 5 Storage database.

Modern browsers provide the JSON.stringify() and JSON.parse() methods to serialize objects to strings and deserialize strings to objects respectively. Older browsers can be brought up to speed with Douglas Crockford's JSON-js library.

For simpler data types, like integers and floats, you can assign them directly, knowing that JavaScript will cast them to string data automatically. This will get you into trouble when you need to retrieve the data later though (see pitfalls below). You're best bet is to explicitly cast the number to string before storing it:

x = 1;
x.toString();

JSON serialization isn't the only way to fit data into a string type. Base 64 encoding is another method. This capability is not built into JavaScript, but there are libraries out there to help: http://www.webtoolkit.info/javascript-base64.html. Be wary of Base 64 encoding though, it can consume a good amount of space (see Base 64 encoding the web).

 

Sounds like a hassle, where's the best place to use HTML Storage

The quick answer is, on mobile web sites. Mobile devices are modern and hence use modern browsers. Modern browsers support HTML 5 Web Storage. People are also a little less concerned about the "dangers" of JavaScript on their mobile device.

HTML 5 Storage on mobile devices also provides a more noticeable performance gain over cookies. Cookies use bandwidth, HTML 5 Storage doesn't. Since bandwidth is at more of a premium on mobile, it makes even more sense.

If you've dabbled in PhoneGap (Cordova) at all, you know how indispensable HTML 5 Storage is.

 

Just tell me how to use it!

I've left the syntax and usage part alone until now, mainly because it's easy. The dependencies, limitations and concepts that surround the usage deserved more attention. The example below demonstrates how to set and retrieve a value, check for the HTML 5 Storage capability, determine whether a key has been created.

if (typeof Storage !== 'undefined') {
    if (localStorage.firstVisit === undefined) {
        localStorage.firstVisit = (new Date()).toString();
    }

    document.write('A loyal visitor since ' + localStorage.firstVisit);
}

 

Common Pitfalls

I've tossed out a lot of nonsense about specifications, limitations, dependencies and data types. But that's all academic. What happens in the real world when we introduce HTML 5 Storage into our applications? I have personally been victim of the following pitfalls and would like to spare you the same!

  • The Counter. Long-term counters are an excellent way to leverage HTML 5 Storage. But, remember that it only allows string data. This doesn't present a problem when you set a value, because JavaScript will convert the number to string for you.

    Once the data is in storage though, JavaScript forgets that it was even a numeric value. When you access it, it will be a string variable. So, the following happens:

    window.localStorage.visits = 0;
    window.localStorage.visits = window.localStorage.visits + 1;
    document.write(window.localStorage.visits);

    "01"

    Essentially, string concatenation was performed instead of integer addition.

    Be sure to cast the string to a numeric type first, before performing any arithmetic:

    window.localStorage.visits = (parseInt(window.localStorage.visits) + 1).toString();
     

  • Storing images. Store small images only, not high-res images. Even if you only plan to store one high-res image and are certain it will be under the 5MB storage limit – avoid this. It is unpredictable across browsers. I've had some browsers return a quota error even though the Base64 encoded image was only around 2MB in size. Whatever your application, I'd recommend using a different approach, such as server-side storage via AJAX.
     
  • The IE 7 false positive. I develop and test most of my code in the Firefox browser, knowing that there are good CSS hacks available for Webkit and IE browsers if needed. Within IE, I use the developer tools to switch the browser and document mode to IE 8 or IE 7 as needed. This is accurate 99% of the time. HTML 5 Web Storage falls in that remaining 1% of capabilities that are not properly emulated.

    When you switch the document and browser mode to IE 7, HTML 5 Web Storage will still be available. Consider using IE Tester. Alternatively, just add the following line at the top of your JavaScript when you test in the IE 7 browser mode.

    Storage = undefined

 

 

Real-world Examples

var webstorageExample = {
    banners: [
        '<img src="/img/banner1.jpg" alt="" />',
        '<img src="/img/banner2.jpg" alt="" />'
    ],
    getBannerIndexLocation: function() {
        if (typeof Storage !== 'undefined') /* must use typeof for IE 7 support */ {
            if (sessionStorage.gutterBannerIndex !== undefined) {
                var bannerIndex = parseInt(sessionStorage.gutterBannerIndex);
                var bannerUpperBounds = webstorageExample.banners.length - 1;
               
                if (bannerIndex < bannerUpperBounds)
                    sessionStorage.gutterBannerIndex = bannerIndex + 1;
                else
                    sessionStorage.gutterBannerIndex = 0;
               
                return bannerIndex;
            }
            else {
                sessionStorage.gutterBannerIndex = 1;
                return 0;
            }
        }
        else {
            /* no web storage support, so just return a random index */
            return (Math.floor(Math.random() * webstorageExample.banners.length));
        }
    },
    getContent: function() {
        var bannerIndex = webstorageExample.getBannerIndexLocation();
        return webstorageExample.banners[bannerIndex];
    }
}

 

This next example was pulled from a Mortgage Calculator app I created. It demonstrates how to fall back on cookies when HTML 5 Storage is unavailable:

function storeJSON(jsonString) {
	if(typeof Storage !== 'undefined') {
		localStorage.loans = jsonString;
	}
	else {
		var date = new Date();
        date.setTime(date.getTime()+(7776000000));
        var expires = "; expires="+date.toGMTString();
		document.cookie = 'loans=' + jsonString + expires;
	}
}

Subscribe

  • follow us in feedly


Tagged , , , , , .

Updated: 2012-12-28

Phil LaNasa