javascript 为什么documentFragment并不比重复的DOM访问快?

k10s72fa  于 2023-05-05  发布在  Java
关注(0)|答案(4)|浏览(138)

我一直有这样的印象,出于性能原因,我们应该使用documentFragment来追加多个元素,然后一次性将片段追加到文档中,而不是一个接一个地重复追加新元素到DOM中。
我一直在尝试使用Chrome的开发工具来分析这两种方法,使用这个测试页面:

<button id="addRows">Add rows</button>
<table id="myTable"></table>

测试1使用以下代码向表中追加50000个新行:

let addRows = document.getElementById('addRows');
addRows.addEventListener('click', function () {
    for (let x = 0; x < 50000; x += 1) {
        let table = document.getElementById('myTable'),
            row = document.createElement('tr'),
            cell = document.createElement('td'),
            cell1 = cell.cloneNode(),
            cell2 = cell.cloneNode(),
            cell3 = cell.cloneNode();

        cell1.textContent = 'A';
        cell2.textContent = 'B';
        cell3.textContent = 'C';

        row.appendChild(cell1);
        row.appendChild(cell2);
        row.appendChild(cell3);
        table.appendChild(row);
    }
});

在Chrome的时间轴工具中录制时单击该按钮会产生以下输出:

测试2使用以下代码:

let addRows = document.getElementById('addRows');
addRows.addEventListener('click', function () {
    let table = document.getElementById('myTable'),
        cell = document.createElement('td'),
        docFragment = document.createDocumentFragment();

    for (let x = 0; x < 50000; x += 1) {
        let row = document.createElement('tr'),
            cell1 = cell.cloneNode(),
            cell2 = cell.cloneNode(),
            cell3 = cell.cloneNode();

        cell1.textContent = 'A';
        cell2.textContent = 'B';
        cell3.textContent = 'C';

        row.appendChild(cell1);
        row.appendChild(cell2);
        row.appendChild(cell3);

        docFragment.appendChild(row);
    }

    table.appendChild(docFragment);
});

它的性能配置文件如下所示:

第二个,据说比第一个快得多的替代品,实际上需要更长的时间来运行!我已经多次运行这些测试,有时第二种方法稍微快一点,有时,如这些图像所示,第二种方法稍微慢一点,但两种方法之间没有任何显著差异。
这是怎么回事?浏览器是否已经优化得如此之好,以至于不再有任何区别?我是否错误地使用了分析工具?
我在Windows 10上,Chrome 57.0.2987.133

xxe27gdn

xxe27gdn1#

实际上,你的测试代码只是插入节点,而不改变它们的内容或CSS,这实际上会迫使渲染引擎重新进行。
我准备了三个测试来证明这种巨大的差异。
1.简单的DOM修改导致布局垃圾
1.通过window.requestAnimationFrame()进行简单的DOM修改
1.通过document.createDocumentFragment()修改虚拟DOM

备注:

  • 您可能会喜欢在全屏上进行测试。
  • 在Firefox中,我获得了更戏剧性的结果。
// Resets the divs
function resetLayout() {
  divs = document.querySelectorAll('div');
  speed.textContent = "Resetting Layout...";
  setTimeout(function() {
               each.call(divs, function(div) {
                                 div.style.height = '';
                                 div.offsetTop;
                               });
               speed.textContent = "";
             }, 16);
}
// print the result
function renderSpeed(ms) {
  speed.textContent = ms + 'ms';
}

var divs        = document.querySelectorAll('div'),
    raf         = window.requestAnimationFrame,
    each        = Array.prototype.forEach,
    isAfterVdom = false,
    start       = 0;

// Reset the Layout

reset.onclick = resetLayout;

// Direct DOM Access

direct.onclick = function() {
                   isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                   start = performance.now();

                   each.call(divs, function(div) {
                   var width = div.clientWidth;
                   div.style.height = ~~(Math.random()*2*width+6) + 'px';
                   div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                 });

                   // Render result
                   renderSpeed(performance.now() - start);
                 };

// Access DOM at the next frame by requestAnimationFrame

rAF.onclick = function() {
                isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                start = performance.now();

                each.call(divs, function(div) {
                                  var width = div.clientWidth;
                                  // Schedule the write operation to be run in the next frame.
                                  raf(function() {
                                        div.style.height = ~~(Math.random()*2*width+6) + 'px';
                                        div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                                      });
                                });
               // Render result
               raf(function() {
                     renderSpeed(performance.now() - start);
                   });
             };

// Update the vDOM and access DOM just once by rAF

vdom.onclick = function() {
                 var sectCl = divCompartment.cloneNode(true),
                     divsCl = sectCl.querySelectorAll('div'),
                     dFrag  = document.createDocumentFragment(),
                     width  = divCompartment.querySelector('div').clientWidth;
                 
                 isAfterVdom = true;
                 end = 0;
                 start  = performance.now();
                 each.call(divsCl, function(div) {
                                     div.style.height = ~~(Math.random()*2*width+6) + 'px';
                                     div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                                   });
                 dFrag.appendChild(sectCl);
                 divCompartment.parentNode.replaceChild(dFrag, divCompartment);
                 // Render result
                 renderSpeed(performance.now() - start);
               };
html {
  font: 14px Helvetica, sans-serif;
  background: black;
  color: white;
}

* {
  box-sizing: border-box;
  margin-bottom: 1rem;
}

h1 {
  font-size: 2em;
  //word-break: break-word;
  -webkit-hyphens: auto;
}

button {
  background-color: white;
}

div {
  display: inline-block;
  width: 5%;
  margin: 3px;
  background: white;
  border: solid 2px white;
  border-radius: 10px
}

section {
  overflow: hidden;
}

#speed {
  font-size: 2.4em;
}
<body>
  <h1>Updating 1000 DOM Nodes</h1>
  <section>
    <button id="reset">Reset Layout</button>
    <button id="direct">Update Directly</button>
    <button id="rAF">Update by rAF</button>
    <button id="vdom">Update by vDOM</button>
    <section id="speed"></section>
    <section id="divCompartment">
      <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
    </section>
</body>
vlju58qv

vlju58qv2#

对不起...由于答案的30000个字符限制和前一个的长度,我不得不放置另一个作为我前一个答案的扩展。
我想每个人都听说了直接访问DOM是不好的...是的,这就是我一直被告知的,因此我相信虚拟DOM方法的正确性。虽然我不太明白的事实是,虽然DOM和vDOM都表示在内存中,为什么一个比另一个快?实际上,在进一步扩展我的测试中,我开始相信真实的的瓶颈归结为JS引擎的性能,如果你正确地更新DOM。
现在让我们想象一下有1000个div在background-color和height CSS属性上重复更新的情况。
如果直接在DOM元素上执行此操作,则只需保留这些元素的nodeList,并简单地更改它们的style.backgroundColorstyle.heigth属性。
如果您通过文档片段来实现这一点,那么您显然可以不用多次接触DOM,而是首先必须
1.克隆1000个div元素的父容器。
1.访问包含div(如parent.children)的nodeList
1.对每个div元素执行必要的改变,
1.创建文档片段
1.重新克隆先前克隆的父容器元素(步骤1)并将其附加到文档片段(或者,如果需要新的容器,您可以选择从DOM克隆div的容器,但每次修改都必须以这种或那种方式克隆它们)
1.将文档片段附加到DOM中div容器的父级,并删除旧的div容器。基本上是Node.replaceChild操作。
事实上,对于这个测试,我们不需要文档片段,因为我们不创建新节点,而只是更新已经存在的节点。因此,我们可以跳过步骤4,在步骤5中,我们可以直接使用divs容器的克隆副本作为replaceChild操作的源。
如何正确更新DOM?绝对异步。因此,对于前面的示例,如果您将直接更新部分移动到异步时间轴(如setTimeout(_ => renderDirect(),0)),则它将是所有时间线中最快的。但是,然后反复更新圆顶可以有点棘手。
实现这一点的一种方法是重复地向setTimeout(_ => renderDirect(),0)提供我们的DOM更新,如。

for (var i = 0; i < cnt; i++) setTimeout(_ => renderDirect(divs,width),0);

在上述情况下,JS引擎的性能对结果非常重要。如果我们的代码太轻,那么多个周期将堆叠在一个DOM更新上,我们将只观察其中的一小部分。在这个特定的情况下,我们只能看到50个更新中的9个。

因此,进一步推迟每一轮可能是一个好主意。那么怎么样;

for (var i = 0; i < cnt; i++) setTimeout(_ => renderDirect(divs,width),i*17);

好吧,这是好得多,我有22个实际上画在我的屏幕上的50个更新。所以它碰巧是,如果延迟被选择为足够长,你会有所有的帧画。但多久是个问题。因为如果它太长,你有空闲时间为您的渲染引擎,它类似于缓慢的DOM更新。因此,对于这个特定的测试,结果是29- 30 ms左右...是在1400 ms内观察所有1000个div的50个单独DOM更新的最佳值。至少在我的桌面上有Chrome。根据硬件或浏览器的不同,您可能会看到完全不同的东西。

所以setTimeout分辨率对我来说看起来不太有希望。我们必须使这项工作自动化。幸运的是,我们有合适的工具来完成这项工作。RAF再次提供帮助。我提出了一个帮助函数来滥用rAF(requestAnimationFrame)。我们将通过直接访问下一个可用动画帧的DOM,一次性更新1000个div。当我们仍然在异步时间轴中时,我们将从当前执行的回调中请求另一个动画帧。因此,从rAF的回调递归地调用另一个rAF。我将此函数命名为looper

var looper = n => n && raf(_ => (renderDirect(divs, width),looper(--n)));

这是一个ES6代码。所以让我把它翻译成类JS。

function looper(n){
  if (n !== 0) {
    window.requestAnimationFrame(function(){
                                   renderDirect(divs,width);
                                   looper(n-1);
                                 });
  }
}

现在一切都应该自动化。它看起来很酷,在1385 ms内完成。

所以现在我们有了更多的知识,我们可以玩代码。

// Resets the divs
function resetLayout() {
  divs = document.querySelectorAll('div');
  speed.textContent = "Resetting Layout...";
  setTimeout(function() {
               each.call(divs, function(div) {
                                 div.style.height = '';
                                 div.backcgoundColor = '';
                               });
               speed.textContent = "";
             }, 16);
}
// print the result
function renderSpeed(ms) {
  speed.textContent = ms + 'ms';
}

function renderDirect(divs,width){
  each.call(divs, function(div) {
                    div.style.height = ~~(Math.random()*2*width+6) + 'px';
                    div.style.backgroundColor = '#' + Math.random().toString(16).substr(-6);
                  });

  // Render result
  renderSpeed(performance.now() - start);
}

function renderByVDOM(sct,prt,wdt){
  var //dFrag = document.createDocumentFragment();
      divs  = sct.children;
  each.call(divs, function(div) {
                    div.style.height = ~~(Math.random()*2*wdt+6) + 'px';
                    div.style.backgroundColor = '#' + Math.random().toString(16).substr(-6);
                  });
  //dFrag.appendChild(sct);
  prt.replaceChild(sct, divCompartment);
  // Render result
  renderSpeed(performance.now() - start);
}

var divs        = document.querySelectorAll('div'),
    width       = divs[1].clientWidth;
    raf         = window.requestAnimationFrame,
    each        = Array.prototype.forEach,
    isAfterVdom = false,
    start       = 0,
    cnt         = 50;

// Reset the Layout

reset.onclick = resetLayout;

// Direct DOM Access

direct.onclick = function() {
                   var looper = n => n && raf(_ => (renderDirect(divs, width),looper(--n)));
                   isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                   start = performance.now();
                   //for (var i = 0; i < cnt; i++) setTimeout(_ => renderDirect(divs,width),i*29);
                   looper(cnt);
                 };

// Update the vDOM and access DOM just once by rAF

vdom.onclick = function() {
                 var sectCl = divCompartment.cloneNode(true),
                     parent = divCompartment.parentNode,
                     looper = n => n && raf(_ => (renderByVDOM(sectCl.cloneNode(true), parent, width),looper(--n)));
                 
                 isAfterVdom = true;
                 start  = performance.now();
                 looper(cnt);
               };
html {
  font: 14px Helvetica, sans-serif;
  background: black;
  color: white;
}

* {
  box-sizing: border-box;
  margin-bottom: 1rem;
}

h1 {
  font-size: 2em;
  -webkit-hyphens: auto;
}

button {
  background-color: white;
}

div {
  display: inline-block;
  width: 5%;
  margin: 3px;
  background: white;
  border: solid 2px white;
  border-radius: 10px
}

section {
  overflow: hidden;
}

#speed {
  font-size: 2.4em;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>repl.it</title>
    <link href="index.css" rel="stylesheet" type="text/css" />
    <script src="index.js" async></script>
  </head>
  <body>
  <h1>Updating 1000 DOM Nodes</h1>
  <section>
    <button id="reset">Reset Layout</button>
    <button id="direct">Update Directly</button>
    <button id="vdom">Update by vDOM</button>
    <section id="speed"></section>
    <section id="divCompartment">
      <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
    </section>
  </section>
</body>
</html>

因此,测试看起来像是通过rAF直接访问比克隆和处理克隆并用它替换旧的要好。特别是当一个巨大的DOM块被替换时,在我看来,GC(垃圾收集)任务会被卷入到工作的中间,事情会变得有点棘手。我不知道如何消除它。你的想法是最受欢迎的。

**A Side Note:**此测试还显示,当前(版本91.0.838.3)的新Chrome Edge Browser执行DOM渲染的速度比当前(版本89.0.4389.114)Chrome快约15%。

7rtdyuoh

7rtdyuoh3#

我不知道如何准确地解释你的分析器结果,但通过benchmark.js测试显示第二个选项在Chrome中更快:https://jsbench.me/awj1gwhk9i/1
FF中也更快(尽管差异较小)

zfciruhq

zfciruhq4#

这个lifehack(最后一个按钮,名为“隐藏/显示”)-https://jsfiddle.net/qnxfhtyL/怎么样?
它基于上述演示,似乎是最简单和最快的-至少对于这个特定的测试。
诀窍是只隐藏html块(divCompary.style.display = 'non'),然后根据需要处理它,然后再次显示出来(divCompary.style.display = 'block')。浏览器将不必重画它1000倍,而它的隐藏。隐藏和展示仍然不被注意。下面是整个代码:

<!doctype html>
<html spellcheck="false">
<head>
</head>
<style>
    html {
    font: 14px Helvetica, sans-serif;
    background-color: white;
    color: black;
    }

    * {
    box-sizing: border-box;
    margin-bottom: 1rem;
    }

    h1 {
    font-size: 2em;
    //word-break: break-word;
    -webkit-hyphens: auto;
    }

    button {
    background-color: white;
    }

    div {
    display: inline-block;
    width: 5%;
    margin: 3px;
    background: white;
    border: solid 2px white;
    border-radius: 10px
    }

    section {
    overflow: hidden;
    }

    #speed {
    font-size: 2.4em;
    }
</style>
<body>
<h1>Updating 1000 DOM Nodes</h1>
<section>
    <button id="reset">Reset Layout</button>
    <button id="direct">Update Directly</button>
    <button id="rAF">Update by rAF</button>
    <button id="vdom">Update by vDOM</button>
    <button id="hide_show">Update by Hide/Show</button>
    <section id="speed"></section>
    <section id="divCompartment">
        <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
    </section>

<script>
    // Resets the divs
    function resetLayout() {
      divs = document.querySelectorAll('div');
      speed.textContent = "Resetting Layout...";
      setTimeout(function() {
                   each.call(divs, function(div) {
                                     div.style.height = '';
                                     div.offsetTop;
                                   });
                   speed.textContent = "";
                 }, 16);
    }
    // print the result
    function renderSpeed(ms) {
      speed.textContent = ms + 'ms';
    }
    
    var divs        = document.querySelectorAll('div'),
        raf         = window.requestAnimationFrame,
        each        = Array.prototype.forEach,
        isAfterVdom = false,
        start       = 0;
    
    // Reset the Layout
    
    reset.onclick = resetLayout;
    
    // Direct DOM Access
    
    direct.onclick = function() {
                       isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                       start = performance.now();
    
                       each.call(divs, function(div) {
                       var width = div.clientWidth;
                       div.style.height = ~~(Math.random()*2*width+6) + 'px';
                       div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                     });
    
                       // Render result
                       renderSpeed(performance.now() - start);
                     };
    
    // Access DOM at the next frame by requestAnimationFrame
    
    rAF.onclick = function() {
                    isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                    start = performance.now();
    
                    each.call(divs, function(div) {
                                      var width = div.clientWidth;
                                      // Schedule the write operation to be run in the next frame.
                                      raf(function() {
                                            div.style.height = ~~(Math.random()*2*width+6) + 'px';
                                            div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                                          });
                                    });
                   // Render result
                   raf(function() {
                         renderSpeed(performance.now() - start);
                       });
                 };
    
    // Update the vDOM and access DOM just once by rAF
    
    vdom.onclick = function() {
                     var sectCl = divCompartment.cloneNode(true),
                         divsCl = sectCl.querySelectorAll('div'),
                         dFrag  = document.createDocumentFragment(),
                         width  = divCompartment.querySelector('div').clientWidth;
                     
                     isAfterVdom = true;
                     end = 0;
                     start  = performance.now();
                     each.call(divsCl, function(div) {
                                         div.style.height = ~~(Math.random()*2*width+6) + 'px';
                                         div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                                       });
                     dFrag.appendChild(sectCl);
                     divCompartment.parentNode.replaceChild(dFrag, divCompartment);
                     // Render result
                     renderSpeed(performance.now() - start);
                   };

    // Hide -> Update -> Show

    hide_show.onclick = function() {
                        isAfterVdom && (divs = document.querySelectorAll('div'), isAfterVdom = false);
                        start = performance.now();
                        width  = divCompartment.querySelector('div').clientWidth;

                        divCompartment.style.display = 'none';
                        each.call(divs, function(div) {
                            div.style.height = ~~(Math.random()*2*width+6) + 'px';
                            div.style.backgroundColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
                        });
                        divCompartment.style.display = 'block';

                        // Render result
                        renderSpeed(performance.now() - start);
                    };
    </script>
  </section>
</body>
</html>

相关问题