With the proliferation of AJAX becoming the flavor of the day for frontend development, in particular, REST APIs, browser performance has become an increasingly important aspect of development that cannot be ignored. Many popular frontend frameworks designed for REST consumption have great methods for caching AJAX results to prevent multiple requests for the same data – Ember Data comes to mind – but outside of using a framework, or in cases where a framework does not support caching, there are options to store data directly in the browser with Web Storage as a replacement for cookies.

What is Web Storage?


Web Storage as an API has been around for a while and supported by IE8. Storage objects work like cookies, allowing you to store and access key→value pairs with the exception is that it is handled directly through the browser with a larger storage size and has two browser-centric expiration modes. To start with storage, each browser handles storage size with Web Storage a little differently and ranges from 5mb per domain (Chrome, Firefox, Opera) and up to 10mb per domain (IE). In contrast to cookies which allows up to 4096 bytes per cookie this means you could, in practice, store about 1250x as much data through Web Storage methods than a single cookie would allow and with that per domain clause mentioned a few times prior, keep all of your data sectioned to your domain without worrying about conflicting namespaces (unless you cause them).

To the second point mentioned: Web Storage allows for two distinctly browser-centric expiration methods. The Web Storage API houses two methods of storage: localStorage and sessionStorage. localStorage is completely persistent, with no expiration date. The only way to remove localStorage is through JavaScript, even after the browser has been closed. The data contained in localStorage is accessible from any script loaded on the same domain at any time. In contrast, sessionStorage is saved on a per window, per domain storage basis and is wiped out whenever the browsing session ends (closing the browser tab/window). This allows for multiple instances of the same application to be run in a browser with separate storage objects, to avoid accessing data meant for another instance.

In short: localStorage is forever, sessionStorage is just for the window/tab you have open.

In addition, like localStorage, sessionStorage also has a size limit but is on top of the localStorage. In essence, you could have your 5mb of localStorage filled up and then have another 5mb of sessionStorage resulting in 10mb of storage being used for caching.

Using Web Storage


Separating the use cases for localStorage and sessionStorage depends on what you plan on accomplishing with your application. Since localStorage is persistent it makes the most sense to use that for application-wide caching or anything that is not bound to a user’s particular data requests. On the other hand, since sessionStorage is unique to a window and domain it makes sense to use this for caching user-centric data that would benefit your application’s performance, such as revisiting a recently loaded API response.

Using the API response example, let’s look at the following snippet for a GET request:

$.get('/user/1/posts', function(response){
	//Set data
	var posts = response;
	renderPostsToPage(posts);
});

Above we are using jQuery to get a response from /user/1/posts to get the posts for user 1 in REST style. Assuming we are receiving posts and it’s relatively quick this isn’t an issue, request on load and display the posts however we want from here. However, let’s assume this response takes 10 seconds. We now have a 10-second window of “loading posts” that will deter users and leave your application feeling sluggish. We can compensate for this on subsequent loads by setting our sessionStorage. First, we’ll get the sessionStorage:

$.get('/user/1/posts', function(response){
	//Set data
	var posts = response;
	renderPostsToPage(posts);

	//Create JSON string for storage
	var postsStorage = JSON.stringify(response);
	sessionStorage.setItem('posts', postsStorage);
});

We are now setting our sessionStorage with a JSON string using the response object – sessionStorage and localStorage do not allow for storing arrays or objects, only strings. We are still setting posts, but we are now also setting the sessionStorage key at the same time using sessionStorage.get() with the first parameter as our key and the second parameter as our value. This allows us to access that object on subsequent requests while still performing the update in the request in the background to update our storage discreetly.

So now we need to access this newly set sessionStorage object before we make the request:

var posts = sessionStorage.getItem('posts');
if(posts){
	posts = JSON.parse(posts);
	renderPostsToPage(posts);
}

$.get('/user/1/posts', function(response){
	//Set data
	var posts = response;
	renderPostsToPage(posts);

	//Create JSON string for storage
	var postsStorage = JSON.stringify(response);
	sessionStorage.setItem('posts', postsStorage);
});

With the addition before our GET request, we are now attempting to retrieve the posts from our sessionStorage with sessionStorage.getItem() using posts as our key – the same key we set earlier with sessionStorage.setItem(). If there is a value in sessionStorage that value will be returned, otherwise a NULL value will be returned. Assuming we get posts back from the sessionStorage retrieval, we parse the JSON and run the renderPostsToPage() function just like when we receive the GET request.

And that is that: On initial load, we wait for the response and cache our posts – then every load after that we will still perform the request but we already have the cached posts from before to render to the page and allow users to use the application immediately while we re-request posts in the background. This is a specific example, but it should still open up ideas for using these APIs to improve your frontend application performance.

By using Web Storage APIs you can greatly improve performance in many ways, such as caching and preventing additional requests (for one-time necessary requests) or, like in the example above, improve user experience by removing the “waiting list” and letting people jump directly into content they’ve already received.

Storage Reference


For quick reference, here is all you can do with the Storage API:

// return number of keys stored on your domain
localStorage.length

// return index of key stored on your domain
localStorage.key(key)

// return particular key→value on your domain
localStorage.getItem(key)

// set key→value item in your domain storage
localStorage.setItem(key, value)

// remove a particular key from storage on your domain
localStorage.removeItem(key)

// removes everything in storage on your domain
localStorage.clear()

* all localStorage references can be replaced by sessionStorage.

In addition here is a little snippet you can use to determine if the Web Storage API is available on the browser you are accessing your application with to prevent your script from failing:

/**
 * Can use cache? 
 */
cacheable: function(){
	if(typeof(Storage) !== "undefined")
		return true;
	else
		return false;
}
var canCache = cacheable(); // returns boolean TRUE if Web Storage is supported.

Originally written for Wide Open Technologies