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.

ABOUT THE AUTHOR
Sergey Chikuyonok photo

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

17 Responses to “HTML Lazy Load”

  1. Tweets that mention Performance Calendar » HTML Lazy Load -- Topsy.com

    [...] This post was mentioned on Twitter by Stoyan Stefanov, john Allsopp and integralist, Nick Sadovnikov. Nick Sadovnikov said: RT @stoyanstefanov: perf advent calendar day 11: Lazy HTML load by @chikuyonok http://perfplanet.com/201011 [...]

  2. Galambosi Balázs

    “You don’t need to show all 500KB text at once”

    In fact you don’t need to send all 500KB text at once. It’s easier to send one Chapter initially, and if the users scrolls enough send the next one, etc. Similarly to how Twitter works.

    Keeping only visible things in memory is a neat technique and it’s also used by online text editors extensively.

  3. Sergey Chikuyonok

    There are single chapters of more that 500KB (actually, there were chapters of more that 1M, especially on user-generated books). Also, e-book engine works as offline application and allows users to upload their own books so there’s no control on what will be sent to browser at all.

  4. Peter

    hi,

    i’m afraid of the possibility, that search engines could interpret my website wrong. there must be some php, too. on this way the browsers could be switched to different content. but i’m not sure, how solid that would be in practice.

    - j

  5. Sergey Chikuyonok

    Peter, this article is not about reasons of commenting your data, but about how to load data faster if you have to.

  6. Johann

    JFTR, I think you might need to use <![CDATA instead of <!– because I think <!– can’t contain unescaped markup.

  7. jpvincent

    how does it compare versus a display:none ?

  8. Anthony Ricaud

    Although this is a good technique for performance, you can only use it when JavaScript is a requirement. I think the article should emphasis this warning. Improving performance is great but it shouldn’t be at the expense of usability and accessibility.

  9. Martin Borthiry

    @jpvincent: the DOM load images inside display:none containers

    @Sergey: would be better use window.onscroll event to uncomment only shown nodes…. Nice post

  10. 第三十天 停止等待

    [...] HTML Lazy Load真有意思,对于小说等文字类型的网站的WPO,简直犹如神器啊!有空一定要深入研究一下。其实我一直想弄个小说网站的,可是,版权呐,我又不敢像百度文库那样堂而皇之的盗版。 [...]

  11. Abrab

    Hi everyone.

    Starting from Sergey’s idea, I’ve begun to develop a script a bit more versatile.
    There is still a lot of improvement to do, but I’d like to test its operation and performances from now.

    Does someone want to try? All you have to do is follow this link: lazyHtml test

    It’s all in french but there’s not much to understand. (In green you’ll see the statistics with Sergey’s trick. In pink the statistics of ordinary rendering.)

  12. kangax

    The idea is interesting and useful. The implementation, however, doesn’t degrade gracefully, and so is inaccessible.

    How about having a CSS rule like “.has-js .chapter { display: none; }” together with adding “has-js” class to a root (or body) element? When JS is available, the “chapter” element is initially hidden (and so doesn’t need to render); otherwise — user gets nicely degradable version with the entire text shown.

    Have you tested the performance of large chunks of text in “display:none” elements?

  13. Steve Clay

    Accessibility issues aside, this could be useful especially when having to display very large data tables in older IE and other tough spots.

  14. Revision 28: Niemand hat Lion oder iOS 5 | Working Draft

    [...] Performance-Kniff, auf den letztes Jahr Sergey Chikuyonok gekommen ist verpackt das HTML einer Seite so, dass es vom Browser zunächst nicht vollständig ausgewertet und [...]

  15. Bricolage

    It’s really helpful,
    thank you

  16. Parijat

    That’s an interesting article. However, there are a few caveats.
    1) It presumes each commented element is a DIV.
    2) It doesn’t take into consideration that you can have comments within commented blocks. Not that this is a biggie, but it requires attention to that detail else you risk rendering actual comments into your browser
    3) declares var el multiple times within the for loop, might want to move its declaration outside.

    It’s still a very cool article, thanks for posting it.

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
And here's a tool to convert HTML entities