boldr by Nicolas Mérouze

Speed up Ajax with HTML5 Web Storage

I'm beginning a series of articles about the modern features of Web browsers. This article will be about HTML5 Web Storage and particularly localStorage. And because I like it, another twitter example folks!

What is localStorage?

Compatibility of localStorage (as of January 2010) : IE8, Firefox 3.5, Safari 4, Chrome 4, Opera 10.50

Basically it's like cookies but restricted to the client (the server cannot get data from localStorage), it can store more data (the limit depends of the browser but it's generally 5MB) and it doesn't have a time expiration. It's time for the example!

WARNING: You must test the above example with a real URL (not file://). Otherwise it won't work in IE and Firefox (but seems to be fine in Safari and Chrome)

The slow way

First we get the tweets and display them. It is slow because each time we access the page the Javascript will request Twitter. And it's ugly because we have a loading message before displaying the tweets.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
  <script type="text/javascript">
    function displayTweets(data) {
      $("#loading").remove();
      $.each(data.results, function(i, item) {
        $("#tweets").append($("<li/>").text(item.text));
      });
    }

    $(function() {
      $("#tweets").before($("<div id='loading'/>").text("Loading..."));
      $.getJSON("http://search.twitter.com/search.json?q=from:nmerouze&rpp=5&callback=?", function(data) {
        displayTweets(data);
      });
    });
  </script>
</head>
<body>
  <ul id="tweets"></ul>
</body>
</html>

To display the tweets instantly we're gonna store them.

Setter

After each request to Twitter we store the whole JSON response to localStorage. It is just one line:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
  <script type="text/javascript">
    function displayTweets(data) {
      $("#loading").remove();
      $.each(data.results, function(i, item) {
        $("#tweets").append($("<li/>").text(item.text));
      });
    }

    $(function() {
      $.getJSON("http://search.twitter.com/search.json?q=from:nmerouze&rpp=5&callback=?", function(data) {
        displayTweets(data);
        localStorage.setItem("tweets", JSON.stringify(data));
      });
    });
  </script>
</head>
<body>
  <ul id="tweets"></ul>
</body>
</html>

localStorage.setItem(key, value) take a key for the first argument ("tweets" here) and the value for the second argument (the Twitter JSON response here). WARNING: The value must be a string so if we want to store an object, we stringify it with JSON.stringify(data).

Getter

Then we write the code to get the tweets from localStorage.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
  <script type="text/javascript">
    function displayTweets(data) {
      $("#loading").remove();
      $("#tweets").children().remove();
      $.each(data.results, function(i, item) {
        $("#tweets").append($("<li/>").text(item.text));
      });
    }

    $(function() {
      $("#tweets").before($("<div id='loading'/>").text("Loading..."));
      var tweets = localStorage.getItem("tweets");
      if (tweets != null) displayTweets(JSON.parse(tweets));
      $.getJSON("http://search.twitter.com/search.json?q=from:nmerouze&rpp=5&callback=?", function(data) {
        displayTweets(data);
        localStorage.setItem("tweets", JSON.stringify(data));
      });
    });
  </script>
</head>
<body>
  <ul id="tweets"></ul>
  <button onclick="javascript:localStorage.clear();">Clear localStorage</button>
</body>
</html>

To get the data it's localStorage.getItem(key). If there's something in it we display them. The first time we access the page there won't be anything in localStorage so the process will be the same as "The slow way". The other times the tweets will be displayed instantly. The Twitter request is running too, so it will refresh the list a little bit after the first display in case there's any new tweets. The rendering will be way prettier than the loading message! You can see the example here.

If we want to clear the localStorage it's as simple as localStorage.clear().

Old browsers compatibility (progressive enhancement)

If you do that in production, the Javascript will fail for the users who have old browsers. To be safe, we will download Modernizr (I will write an article about Modernizr soon) and check if the browser has a localStorage:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
  <script src="modernizr.js" type="text/javascript"></script>
  <script type="text/javascript">
    function displayTweets(data) {
      $("#loading").remove();
      $("#tweets").children().remove();
      $.each(data.results, function(i, item) {
        $("#tweets").append($("<li/>").text(item.text));
      });
    }

    $(function() {
      $("#tweets").before($("<div id='loading'/>").text("Loading..."));
      if (Modernizr.localstorage) {
        var tweets = localStorage.getItem("tweets");
        if (tweets != null) displayTweets(JSON.parse(tweets));
      }
      $.getJSON("http://search.twitter.com/search.json?q=from:nmerouze&rpp=5&callback=?", function(data) {
        displayTweets(data);
        if (Modernizr.localstorage) localStorage.setItem("tweets", JSON.stringify(data));
      });
    });
  </script>
</head>
<body>
  <ul id="tweets"></ul>
</body>
</html>

Result

As a result I made a fork of jQuery tweet with localStorage support, so check it out! You won't see a difference with a server-side rendering.

Links

If you liked the article and/or want to talk to me about it, you can follow me on twitter.