为什么DOM读/写操作的微小重新排序会导致巨大的性能差异

时间:2013-10-08 14:47:24

标签: javascript performance google-chrome firefox dom

以下代码说明了问题,更改读/写顺序会导致执行时间差异很大(使用Chrome,Firefox和IE测试):

// read->write->read->write...
function clearSlow(divs){
    Array.prototype.forEach.call(divs, function(div) {
        contents.push(div.clientWidth);
        div.style.width = "10px";
    });
}
// read->read->...->write->write...
function clearFast(divs){
    Array.prototype.forEach.call(divs, function(div) {
        contents.push(div.clientWidth);
    });
    Array.prototype.forEach.call(divs, function(div) {
        div.style.width = "10px";
    });
}

这是完整示例http://jsfiddle.net/Dq3KZ/2/的JSFiddle。

我的结果为n = 100:
慢版: ~35ms
快速版: ~2ms

对于n = 1000:
慢版: ~2000ms
快速版: ~25ms

我认为这与每种情况下的浏览器重排次数有关。在慢速场景中,每次写入操作都会发生回流。但是,在快速场景中,回流仅在结束时发生一次。但我不确定,我不明白它为什么会这样(当操作是独立的时候)。

修改:我使用了InnerText属性而不是clientWidthStyle.Width,使用谷歌浏览器时我有同样的行为(http://jsfiddle.net/pindexis/CW2BF/7/) 。但是,当使用InnerHTML时,几乎没有差异(http://jsfiddle.net/pindexis/8E5Yj/)。

Edit2:我已经为感兴趣的人打开了关于innerHTML / innerText问题的讨论:why does replacing InnerHTML with innerText causes >15X drop in performance

1 个答案:

答案 0 :(得分:9)

操作并非独立。

当样式或内容大小更改位置或维度时,必须进行重排,因为您请求维度或因为必须更新屏幕(代码完成时)。

div.clientWidth是一个隐藏的函数调用。当您请求此值时,您实际上请求了一个最新值,因此,当样式更改时,您会触发立即重排。

在“快速”情况下,在重新绘制屏幕或请求大小之前,没有理由进行重排。在这种情况下,实际上只需要一次回流。