Use Local Storage to Make Your Single Page Web Application Rock
As I have immersed myself into modern web and mobile architectures I have come to one conclusion, multipage web sites are dead men walking. Constant request, retrieve, react is not a competitive application design going forward. The combination of high speed AJAX browser engines, the rise in mobile platforms and HTML5/CSS3 single page web applications are the here and now.
For developers this means there is a whole new set of problems to solve. How do you load content, markup and other resources? How do you manage it once you have it in the browser?
One strategy is to leverage Application Cache, but the more I have been testing this out and reading about Application Cache the less I like it as a strategy. The concept of an offline application is awesome and one that we need to have a great built in infrastructure to support. However it really seems like this is not the case at the moment.
A few weeks ago I learned about how Google and Bing are leveraging localStorage to store and manage application content. This really peaked my interested as I have been working with localStorage this summer.
How does all this relate back to my single page web application premise? Well one of the problems I have been working through this summer is how to effectively manage application content without overwhelming a device's bandwidth (thinking mobile 3G and battery life) as well as the browser's memory thresholds. To test a theory out I created a simple 3 page web application.
The application contains three pages, named Home, Page 2 and Page 3 (see I told you it was simple). When the initial page is requested it leverages jQuery's $.get method to load the content for pages 2 and 3 when the page loads. Once the content is loaded it is stored in localStorage.
Why localStorage?
If you have not heard about localStorage it is not really a new feature to browsers, but is considered part of HTML5. Believe it or not Internet Explorer 8 supports localStorage. Basically it gives you a sandboxed place to hold data specific to your application. The standard amount is 5MB, but your mileage may vary.
Browser localStorage gives you a place to store string based data, sorry no binaries in here. But for the bulk of a web application's content this will work nicely. It stores your data in a hash table of sorts, where each entry has a key associated with it. You simply call localStorage.keyName to retrieve the value.
Since localStorage will save text data and you can build a simple management layer to manage your content, I like the potential as an offline storage mechanism as well as a tool to limit our need to request content from the server. Of course I would love for a solid mechanism to be included in the browser natively.
Using localStorage for MultipPage Content
First this is a super simple test web page to hold the initial page's content. It also has 3 buttons to swap between pages. I have added some gibberish to simulate actual content.
Home Page
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk sal;dkjf sldkjf sa;'
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk sal;dkjf sldkjf sa;'
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk sal;dkjf sldkjf sa;'
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk sal;dkjf sldkjf sa;'
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk sal;dkjf sldkjf sa;'
The web site has two subsequent pages for the additional pages that look like this:
Page 2
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk ...
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk ...
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk ...
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk ...
kfslakjdf sa;lkjf sdlkfj sa;ljfk sadljfk ...
Now that I have shown you my fancy test pages, let me explain it a bit further. The initial page has all the page stuff like the header, body, etc not shown. But it contains a DIV called 'wrapper'. This is used to wrap the page's content, hence the name of course.
Now let's look at the script that drives this application. In the jQuery Ready method the script loads the content for page's 2 & 3. In the $.get callback it saves the content (data) returned from the server to localStorage using the setItem method. But after those two page's are stored it then grabs the markup contained within the #wrapper DIV, remember this is the home page's content, and stores it in localStorage.
If you noticed I styled the DIV to be initially hidden. This gives me the ability to make a more grand entrance with a transition animation. The script uses a simple $.fadeIn to simulate something cool.
$(document).ready(function () { $.get('defered1.htm', function (data) { localStorage.setItem("page2", data); }); $.get('defered2.htm', function (data) { localStorage.setItem("page3", data); }); localStorage.setItem("homepage", $("#wrapper").html()); $("#homepage").fadeIn(500); $("#btnHome").click(function (e) { e.preventDefault(); $("#wrapper > div").fadeOut(function (e) { $(this).remove(); $("#wrapper").append(localStorage.homepage); $("#homepage").fadeIn(500); }); }); $("#btn2").click(function (e) { e.preventDefault(); $("#wrapper > div").fadeOut(function (e) { $(this).remove(); $("#wrapper").append(localStorage.page2); $("#page2").fadeIn(500); }); }); $("#btn3").click(function (e) { e.preventDefault(); $("#wrapper > div").fadeOut(function (e) { $(this).remove(); $("#wrapper").append(window.localStorage.page3); $("#page3").fadeIn(500); }); }); });
Now when each one of the button's are clicked (or touched) the existing content is faded from view. When that content has faded out it is removed from the page. This is important because we don't need the markup anymore, and if we do we can restore it. But you want to do this because this keeps the size of the page smaller, thus reducing the amount of memory the browser needs to run the page.
The requested page's content is then loaded from localStorage, localStorage.[page name] and appended to the #wrapper div. It is then faded into view. Pretty cool huh?
So let me review, we loaded the application's default page, then asynchronously loaded the balance of the application's content and stored it locally. On demand we load the content from local storage. By doing this we have reduced the amount of network traffic, increased the application's speed as well as minimized the application's memory footprint. On top of all that we now have the ability to integrate some cool content or page transitions.
Of course there is a lot more that could be added to this example. For one we could load the child page's content on demand instead of when the initial page is loaded. Anticipating what a user will do next is fun too.
If you read about how Google and Bing are using this technique. They are leveraging cookies to check for newer versions of content. having up to date content is important for any application native or web. Another thing that I may blog about in the near future is storing data in localStorage and running it through the jQuery template plugin to dynamically create the markup.
I hope this gets you thinking and helps you create better mobile and desktop applications going forward.