gpt4 book ai didi

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

转载 作者:数据小太阳 更新时间:2023-10-29 04:31:51 26 4
gpt4 key购买 nike

我一直认为,出于性能原因,与其反复接触 DOM,不如使用 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 的时间轴工具中录制时单击按钮会产生以下输出:

Repeated DOM interaction

测试 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);
});

它有这样的性能配置文件:

enter image description here

第二个,据说比第一个快得多,实际上需要更长的时间来运行!我已经多次运行这些测试,有时第二种方法稍快一些,有时,如这些图像所示,第二种方法稍慢一些,但这两种方法之间没有一次有任何显着差异。

这里发生了什么?浏览器是否优化得如此之好,以至于这不再有什么区别了?我是否错误地使用了分析工具?

我在 Windows 10 上,Chrome 57.0.2987.133

最佳答案

好吧,实际上您的测试代码只是插入节点而不更改它们的内容或 CSS,这实际上会强制渲染引擎进行重排。

我准备了 3 个测试来证明这种显着差异。

  1. 简单的 DOM 修改导致布局垃圾
  2. 通过 window.requestAnimationFrame() 进行简单的 DOM 修改
  3. 通过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>

关于javascript - 为什么 documentFragment 不比重复的 DOM 访问快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43401497/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com