Web Performance Calendar

The speed geek's favorite time of year
2010 Edition
ABOUT THE AUTHOR
Sergey Chikuyonok photo

Sergey Chikuyonok (@chikuyonok) is an image optimization expert and mobile performance explorer.

If you’re developing a web app that requires to load and show large HTML chunks (for example, an e-book reader), this trick may help your app to be more responsive, especially on mobile devices.

Let’s say, for example, you have load and show a few chapters for Leo Tolstoy’s “War and Peace” book (500KB HTML page) on iPhone. On my test environment (iPhone 2G with v3.1 firmware, files are loaded directly from iPhone to exclude network lags) the page parsing and rendering took about 7 seconds. During this time, user see a blank page and frozen interface; after the page is loaded the interface interaction is still clunky and requires some time to smooth again. In other words, user perception is really poor.

Why so slow?

What makes page rendering so slow? Well, it’s pretty simple: when HTML page is loaded, browser needs to do a lot work. It has to parse HTML, build elements collections (so things like getElementsByTagName() can work faster), match CSS rules, etc., etc. And then, finally, render all those elements—you may know this process as repaint. Repainting is one of the slowest process in browsers and it’s extremely slow on mobile devices. Thus, you have to avoid repaints in mobile browsers at all costs if you want to create a fast and responsive web-site.

But let’s look at this problem from the other side. Mobile devices has very limited display resolution. You don’t need to show all 500KB text at once, you can pick a first few sentences and push them to the screen so the user can start reading while browser parses the rest of the page.

Lazy load to the rescue

To make all this large text invisible to the browser, all we have to do is to comment it:

<body>
    <!--
    <p>Well, Prince, so Genoa and Lucca are now just family estates...</p>
    -->
 
</body>

When the text content was commented out, the page parsing took about 350 ms on my test environment. In this time a had a completely parsed and loaded page so I can work with it with JavaScript.

So, we have a commented text, what now? Actually, HTML comment is not just a hidden code chunk, it’s a DOM node which can be easily accessed. Now we need to find this node and parse its content into a DOM tree:

var elems = document.body.childNodes;
 
for (var i = 0, il = elems.length; i < il; i++) {
  var el = elems[i];
  if (el.nodeType == 8) { //it's a comment
    var div = document.createElement('div');
    div.innerHTML = el.nodeValue;
    // now DIV element contains parsed DOM elements so we can work with them
    break;
  }
}

Since such plain text parsing doesn’t require browser to do CSS matching, repainting and other stuff that it normally does on page parsing, it also performs very fast: about 200 ms in my test environment.

Thus, page loading and parsing took about 550 ms versus 7000 ms in first example and you have a full page’s DOM tree. Now you can pop a few sentences from the list push them to the screen so the user can start reading immediately. The rest elements can be added to the page progressively, chunk by chunk with setTimeout() to prevent interface blocking. My mobile e-book reader engine uses more complex technique: it calculates every element’s dimensions, expands viewport height and adds only those elements that user can see and scroll to, while removing all the rest elements. This technique also increases interface speed and responsiveness and reduces memory footprint.