我有以下代码,循环遍历DOM对象数组,运行测试并在返回true时向节点附加一些文本。
$.each( selections, function ( i, e ) {
var test = some_test(e);
if(test) {
$(e).append('passed');
}
});
虽然这段代码运行良好,但在大型集合中,它显然会对DOM执行大量附加操作。本文on reasons to use append correctly演示了如何更好地添加DOM:
var arr = reallyLongArray;
var textToInsert = [];
var i = 0;
$.each(arr, function(count, item) {
textToInsert[i++] = '<tr><td name="pieTD">';
textToInsert[i++] = item;
textToInsert[i++] = '</td></tr>';
});
$('table').append(textToInsert.join(''));
我的问题是,在不必为每个元素调用.append
的情况下,对一组现有DOM元素进行更改的最高效方法是什么?上面的示例演示了如何创建新元素。这是唯一的方法吗?
答案 0 :(得分:1)
使实时DOM操作变慢的原因主要在于它导致大多数操作的DOM重排。因此,您应该通过减少实时DOM操作的数量来努力减少DOM回流量。
如果要操作已经是DOM的一部分的多个元素,可以使用的一个策略是临时从DOM中删除这些节点的父节点,操纵元素然后将父节点重新附加到其中是
在下面的示例中,我在操作它的行之前分离表,然后将其重新附加到DOM。那是2的回流而不是回流。
var data = [1, 2, 3, 4, 5, 6, 7];
populateCells(document.querySelector('table'), data);
function populateCells(table, data) {
var rows = table.rows,
reAttachTable = temporarilyDetachEl(table);
data.forEach(function (num, i) {
rows[i].cells[0].innerHTML = num;
});
reAttachTable();
}
function temporarilyDetachEl(el) {
var parent = el.parentNode,
nextSibling = el.nextSibling;
parent.removeChild(el);
return function () {
if (nextSibling) parent.insertBefore(el, nextSibling);
else parent.appendChild(el);
};
}
&#13;
<table>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
</table>
&#13;
答案 1 :(得分:0)
您可以使用链接文章中的一种技术完全重建DOM元素集,然后清除现有集和.append()
新集。但鉴于您已经拥有该设置并且只想调整其项目的子集,您的现有代码没有任何问题。
答案 2 :(得分:0)
在谈论性能时,最好对代码进行分析,以便您不必猜测。
以下是围绕此示例的简单测试用例:
http://jsperf.com/most-performant-way-to-append-to-dom-elements
(和相关的小提琴演示这个视觉方面:http://jsfiddle.net/f62ptjbf/)
此测试比较了四种可能的方法:(绝不涵盖所有解决方案)
SPAN
节点(对您的示例略有不同)selection
元素,对其进行操作,然后重新添加到DOM。它表明[至少在我的Chrome浏览器副本中]最快的方法是在处理之前删除元素,然后在处理后重新添加到DOM。 (#4)
以下是另一项测试,显示[至少在我的Chrome副本中]使用“传递”文本附加SPAN
元素比附加文本节点更快。
http://jsperf.com/append-variations
根据这些调查结果,我建议您对代码进行两项潜在的性能改进:
selection
中的DOM元素,然后在完成时重新添加。SPAN
文字“已通过”,而不是直接附加文字。但是,如果元素具有共享父元素,则#1效果最佳。性能将取决于append
操作的数量。