简体   繁体   中英

Why does Chrome render JavaScript so slowly?

I have a page that contains a random number of rows, each row has 2 cols. The challenge is to make this two columns of the same height for each row. I do that with JS.

var len = document.getElementById("translateContainer").children.length;

for(var i = 0; i<len; i++)
{
    var height = document.getElementById("origin_"+i).offsetHeight + 'px',
        col1 = document.getElementById("column_"+i),
        col2 = document.getElementById("column_sec_"+i);

    console.log(i);

    col1.style.height = height;
    col2.style.height = height;
}

When on page are less then 30-40 rows it's all good. But, when there is more then 200 rows, chrome start to lag for a couple of secs.

I've created a demo page here http://jsfiddle.net/YSp76/ .

In FF and IE it executes in about 2sec. In chrome I didn't count but is more then 10.

The problem is in my code or is a webkit bug?

It's not a bug, it's just a result of webkit/blink's non-optimal layout strategy. Here's what's going on behind the scenes:

  • Changing the column height "invalidates" the layout.
  • Querying an offsetHeight requires a valid layout. If the layout is invalid, chrome needs to re-layout the invalid elements.

This means that Chrome will re-layout the page 300 times. If you have access to a Mac, Safari 7.0 has excellent tools for debugging this sort of thing (the 'layout timeline'). Chrome also has some debugging tools in the "timeline" view (filter it so only 'Rendering' events appear). For more information on avoiding layouts, see http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html , although the information presented there is incomplete. Unfortunately, the only up-to-date source on the details of the WebKit rendering process is the WebKit source code itself.

To fix your problem, you can simply separate the querying height step from the changing height step. This will avoid unnecessary layouts. I've forked your fiddle here: http://jsfiddle.net/4fb2A/

var len = document.getElementById("translateContainer").children.length;

var origin_height = [];

for(var i = 0; i<len; i++)
{
    origin_height[i] = document.getElementById("origin_"+i).offsetHeight + 'px';
}

for(var i = 0; i<len; i++)
{
    var height = origin_height[i],
        col1 = document.getElementById("column_"+i),
        col2 = document.getElementById("column_sec_"+i);

    console.log(i);

    col1.style.height = height;
    col2.style.height = height;
}

However, for layout tasks like this, you should try very hard to create a CSS-only solution. Using script is an inappropriate tool for this job, and will alienate visitors who have script turned off.

The chrome profiler (available via right click, inspect element, Profiles) shows that it's the offsetHeight that consumes the largest part, it seems related to this open bug in chrome:

在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM