Firefox 4: Better performance with Lazy Frame Construction

This is a re-post from Timothy Nikkel’s blog.

Lazy Frame Construction is new to Gecko and allows many DOM operations (appendChild, insertBefore, etc) to not trigger immediate reflows. This can vastly improve the interactive performance of very complex web pages. If you want to test this out, you should get a Firefox Nightly.

Lazy frame construction recently landed on mozilla-central. To explain what this means and how this improves things we need some background. Each node in the DOM tree of a webpage has a frame created for it that is used to determine where on the page the node is drawn and its size. A frame corresponds closely to the concept of a box from the CSS spec. We used to create frames for DOM nodes eagerly; that is as soon as a node was inserted into the document we would create a frame for it. But this can create wasted effort in many situations. For example if a script inserts a large number of nodes into the DOM we would create a frame for each node when it is inserted. But with lazy frame construction we can process all those nodes at once in a big batch, saving overhead. Furthermore the time it takes to create those frames no longer blocks that script, so the script can go and do what it needs to and the frames will get created when they are needed. There are other situations where a script would insert nodes into the document and remove them immediately, so there is no need to ever create a frame for these as they would never be painted on screen.

So now when a node is inserted into a document the node is flagged for needing a frame created for it, and then the next time the refresh driver notifies (currently at 20 ms intervals) the frame is created. The refresh driver is also what drives reflow of webpages and CSS & SVG animations.

Let’s look at two examples where lazy frame construction helps.

In this example we insert 80000 div elements and then we flush all pending layout to time how long it takes before the changes made by the script are done and visible to the user. The script can continue executing without flushing layout, but we do it here to measure how long the actual work takes.

var stime = new Date();
var container = document.getElementById("container");
var lastchild = document.getElementById("lastchild");
for (var i = 0; i < 80000; i++) {
  var div = document.createElement("div");
  container.insertBefore(div, lastchild);
document.documentElement.offsetLeft; // flush layout
var now = new Date();
var millisecondselapsed = (now.getTime() - stime.getTime());

With lazy frame construction we are able to process the insertion of all 80000 div elements in one operation, saving the overhead of 80000 different inserts. In a build without lazy frame construction I get an average time of 1358 ms, with lazy frame construction I get 777 ms.

This example comes from a real webpage. We append a div and then set “ = ‘absolute’;”, and repeat that 2000 times, and then we flush all pending layout to time how long it takes before the changes made by the script are done and visible to the user.

var stime = new Date();
var container = document.getElementById("container2");
for (var i = 0; i < 2000; i++) {
  var div = document.createElement("div");
  container.appendChild(div); = "absolute";
document.documentElement.offsetLeft; // flush layout
var now = new Date();
var millisecondselapsed = (now.getTime() - stime.getTime());

With lazy frame construction we don't even bother creating the frame for the div until after the position has been set to absolute, so we don't waste any effort. In a build without lazy frame construction I get an average time of 4730 ms, with lazy frame construction I get 130 ms.

About Paul Rouget

Paul is a Firefox developer.

More articles by Paul Rouget…


  1. myname

    18327 (and frozen browser after test) vs 7437 (no problems with browser)


    May 26th, 2010 at 06:24

  2. Pino

    The second test gives an impressive result indeed, but the first test scores 8000ms both on Firefox 3.6.4 (test build) and 8000 on Minefield as well. No idea if my situation is special or there is something wrong…

    May 26th, 2010 at 06:32

  3. Pavel Dudrenov

    That’s pretty cool, it’s a step closer to something that I really wanted to see in dom for ages now. And that’s sort of atomic operations, as in: document.atomic(function(){/* tons of dom manipulations here */}) where atomic would not do any redraws, or something of that sort. Of caurse you can achieve some of that now with innerHTML, but not all. Anyway thats’s off topic.

    Lazy frame construction is a good idea and it’ll make a lot of pages faster. Good job guys.

    May 26th, 2010 at 07:42

    1. Boris

      Pavel, all JS scripts are “atomic” in the sense you describe. The only question is what the UA manages to defer to the end of the script execution. Pretty much any modern UA defers layout, style computation, painting. Some defer rendering object construction (that’s what this article is about).

      May 26th, 2010 at 09:07

      1. Pavel

        I guess “atomic” is the wrong name for it. I ment that no redraws will happen, as some redraws do happen in the middle of your script.

        May 26th, 2010 at 10:55

        1. Boris

          Pavel, right now redraws don’t happen in the middle of scripts (setting aside sync XHR and modal dialogs) in any modern browser that I know of.

          May 26th, 2010 at 12:36

          1. pavel

            what about el.offsetHeight for example

            May 26th, 2010 at 15:31

          2. Boris

            If you do el.offsetHeight, then the browser has to do layout (but not drawing). This would be the case no matter what, even if the “atomic” API you suggest were added (since anything else would lead to weird races and scripts working or not depending on hardware, os, time of day, etc details).

            May 26th, 2010 at 19:03

  4. Richard Le Poidevin

    Very impressive. I got:
    Test 1: 10489 -> 1333
    Test 2: 3288 -> 507

    May 26th, 2010 at 09:04

  5. LonerGoth

    Test One Result – 25731
    Test Two Result -6851

    firefox 3.6.4.
    ms windows 7 home premium 32-bit

    Samsung R720 Laptop with:
    pentium dual-core cpu t4300 @ 2.10GHz
    4.0 Gb Ram
    ATI mobility Radeon HD 4300 series.

    May 26th, 2010 at 09:48

  6. LonerGoth

    3.7a5pre updated 26/05/2010, 17:50
    test one: 1686ms
    test two: 665ms

    Dramatic improvement. Thanks!

    May 26th, 2010 at 09:55

  7. LonerGoth

    Sorry, I’m in the UK, and I used my local GMT + 0 (UTC + 0) time…

    May 26th, 2010 at 09:56

  8. CaChi

    Test 1 -> 3994
    Test 2 -> 5755

    May 26th, 2010 at 10:32

  9. homm

    Firefox 3.6
    2500 ms
    5500 ms

    Firefox 4 This build
    1660 ms
    193 ms

    Chrome 5.0
    184173 ms !!!
    111 ms

    Opera 10.54
    1300 ms
    50 ms

    Firefox 4 have high CPU usage and freezes after tests when scrolling page and switch to another application. Opera steel work pretty fast.

    May 26th, 2010 at 11:29

  10. sawrub

    Firefox 3.5.9 [Fedora] release.
    Test 1 took around 4k in first second and third attempt.
    Test 2 took around 9k in first attempt,60K in second and had to kill Firefox in third attempt as the CPU usage was 100% for more than 3 minutes i tested it for.

    Tested the same script with Chrome 5 [Fedora] and the biggest difference that i saw was the freezing irrespective of the time taken by each. Running the script in Firefox freezes the whole application,Switching to another tab in FF was not possible. Doing the same in Chrome just freezes that tab, while one can use other tabs independent of the one under test. Testing in Chrome seems like different browser, though it was tested on same lines as FF.
    Really sad to see the freeze on Firefox.

    May 26th, 2010 at 19:59

  11. Lumi

    Seamonkey 2.1a1pre build: 20100509010325
    Test1 – 5433
    Test2 – 2108

    May 27th, 2010 at 00:35

  12. carol

    first test 1056 ms
    second 466 ms

    i dont know its real world value say in regular test but anything that rise result this mutch should be good in my book all things being fairly equal!

    May 27th, 2010 at 08:26

  13. Wurdebalg Hurrst

    I wonder if this is related to the IE Testcenter test with revealing the hexagon tiles, ie. if it makes Firefox better in this particular test.

    May 27th, 2010 at 12:00

  14. Benben

    I can not find the element with id=”lastchild” in the page
    was that voluntary ?

    May 28th, 2010 at 13:35

  15. Tyler Durden

    I don’t think these micro-benchmark are fair for cross-browser comparison.

    Anyway, it would be nice to have another more real-world benchmark using document.createDocumentFragment(). Indeed I thought that this method was created to tackle this issue in the first place.

    And I agree with Pavel Dudrenov : having a new document.atomic function that allow developper to control browser reflow could be interesting. Having “atomic” reflow could benefits to a lot of web app, but it could also lead to a lot of trouble if it is misused….

    May 29th, 2010 at 14:54

  16. Opperhert

    first score appr 2508
    second 4609
    third (after defreezing) 67000

    June 7th, 2010 at 05:43

  17. carol

    first test 981
    second test 407
    not sure if this is intented but if i try the test again without refreshing the page
    those number double (or so)each time so it can get humongous very quick!
    ty for the research love coder who try to simplify instead of complicating
    (a la html5 for exemple)instead of learning the full power of the tool they have at hand like ecmascript5.keep up the good work!

    June 11th, 2010 at 08:46

  18. Ali

    “and then the next time the refresh driver notifies (currently at 20 ms intervals) the frame is created. The refresh driver is also what drives reflow of webpages and CSS & SVG animations”

    So it means a page can only render at max 50 FPS right?

    And Flash Player cannot render faster then that?


    July 6th, 2010 at 14:49

  19. Gilfuin

    72ms in Chrome ;)

    July 7th, 2010 at 06:15

  20. Boris

    > So it means a page can only render at max 50 FPS right?

    Yes. The exact timing might be up to change; there’s a good argument that the right number is 60Hz, not 50Hz.

    Note that your typical modern LCD monitor only refreshes at 60Hz, so painting faster than that is completely pointless.

    > And Flash Player cannot render faster then that?

    It can’t update the on-screen display faster than 60Hz, no. It can, of course, push bits around at a higher rate than that, but no one will see some of those bits. There’s no problem pushing the bits around in Gecko either; it’s just not useful.

    July 7th, 2010 at 17:36

  21. Ali

    Helpful explanation Boris. Thank you.


    July 7th, 2010 at 23:09

  22. […] lazy frame construction の実装 […]

    July 28th, 2010 at 02:35

  23. Anonymous

    Sorry for some off-topic. What about other browsers?
    Opera 10.54: first test: 1335ms, second test: 143ms
    Opera 10.10: first test: 1255ms, second test: 155ms
    Opera 9.64: first test: 2608ms, second test: 163ms
    Opera 8.54: first test: 3950ms, second test: 100ms

    Internet Explorer 7.0: first test: 3400ms, second test: 6775ms.

    Is it not fantastic?

    August 25th, 2010 at 17:33

  24. Marc Dix

    Pretty much differing results…

    Firefox 4.0, Beta 4: 768 ms/330 ms
    Firefox 3.6.8: 1799ms/1293ms
    Chrome 5.0.375.127: 34719ms/68ms
    Safari 5.0.1: 33190ms[freeze]/64ms
    Internet Explorer 8.0.7600.16385: 2231ms/687ms
    Opera 10.61: 578ms/87ms

    August 29th, 2010 at 23:19

  25. Luis Alvarado

    Tested in Ubuntu 10.04.1 with the following results:

    TEST 1 (Initial Test)
    Firefox 3.6.10 – Test 1 – 2840ms
    Firefox 3.6.10 – Test 2 – 3850ms
    Chrome 6.0.472.62 – Test 1 – 31143ms
    Chrome 6.0.472.62 – Test 2 – 71ms

    TEST 2 (Refreshed Page)
    Firefox 3.6.10 – Test 1 – 2830ms
    Firefox 3.6.10 – Test 2 – 4675ms
    Chrome 6.0.472.62 – Test 1 – 29153ms
    Chrome 6.0.472.62 – Test 2 – 64ms

    TEST 3 (Reopened Browsers)
    Firefox 3.6.10 – Test 1 – 2767ms
    Firefox 3.6.10 – Test 2 – 4652ms
    Chrome 6.0.472.62 – Test 1 – 31186ms
    Chrome 6.0.472.62 – Test 2 – 63ms

    September 20th, 2010 at 00:53

  26. edorivai

    Google Chrome just crashed, while Minefield scored an impressive 1400!

    Working on linux btw,

    GJ Guys!

    September 23rd, 2010 at 14:54

  27. Michel

    Windows 7 :
    Firefox 4 beta 7 : first test 1360ms – second test 550ms
    Internet Explorer 9 beta : first test 3749ms – second test 319ms
    Google Chrome Beta 8 : first test FREEZE – second test 211ms

    November 14th, 2010 at 07:36

  28. Shane Bundy

    On Windows 7 ;
    Opera 11.10 (b2039) – 678ms
    Minefield (2011/03/11) – 1473ms
    Chromium (r77944) – 152688ms

    I don’t know whether to be surprised about Opera’s time but I am really surprised on Chromium’s time. I’m sure WebKit uses LFC as well or is it Google’s WebKit mods in Chromium that caused this?

    March 13th, 2011 at 09:51

  29. Shane Bundy

    After I loaded this page I reloaded it and redid the test and got 160ms for Minefield this time (on an old Celeron M 530!)

    March 14th, 2011 at 16:48

    1. Shane Bundy

      Didn’t realise there were 2 tests. My bad.

      On Minefield ;
      Test 1 – 1683ms
      Test 2 – 162ms


      March 14th, 2011 at 16:50

  30. […] More responsive page rendering using lazy frame construction […]

    March 18th, 2011 at 22:59

  31. psxlover

    For me everytime I run one of the tests in Firefox 4 I get a bigger number than before…

    March 22nd, 2011 at 14:05

  32. […] URL field without reloading the page using HTML History APIsMore responsive page rendering using lazy frame constructionLink history lookup is done asynchronously to provide better responsiveness during pageloadCSS […]

    April 10th, 2011 at 22:44

  33. […] More responsive page rendering using lazy frame construction […]

    July 6th, 2011 at 15:38

  34. dang ky ten mien

    thanks for shares

    January 15th, 2012 at 10:48

Comments are closed for this article.