2014-12-02 107 views
0

我有以下代码片段,它循环遍历DOM对象数组,运行测试并向节点追加一些文本(如果返回true)。表现形式附加到现有DOM元素数组

$.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('')); 

我的问题是什么来修改一组现有的DOM元素,而无需调用每个元素.append最高效的方法是什么?上面的例子演示了创建一个新元素。这是唯一的方法吗?

+0

我不明白这个问题。 'append'添加一个新的元素。您不应该使用'append'来修改现有的元素 – jasonscript 2014-12-02 01:18:49

+0

一般的做法是尽可能延缓对DOM的修改。 DOM的每个更改都会分别重新绘制。这适用于添加新元素并对现有元素进行更改 – jasonscript 2014-12-02 01:20:15

+0

请注意,您阅读的文章已超过5年。浏览器引擎已经移动。 “更多”已成为“有时更多”。就你而言,你已经注意到,特定的“优化”甚至不适用。用你已有的东西去做,它最具可读性。 – Bergi 2014-12-02 01:34:42

回答

0

您可以使用链接文章中的技术之一完全重建DOM元素集,然后清除现有集和新的集。但考虑到你已经有了这个集合并且只想调整它的一个子集,你现有的代码并没有什么问题。

1

什么让生活DOM操作缓慢主要是它导致大多数操作进行DOM回流的事实。因此,您应该努力通过减少活动DOM操作的数量来减少DOM回流量。

如果要操作已经是DOM一部分的多个元素,可以使用的一种策略是临时从DOM删除这些节点的父代,操作元素,然后将父节点重新附加到其中它是。

在下面的示例中,我在操作它的行之前先分离表,然后将它重新附加到DOM。这是2次回流,而不是n次回流。

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

0

在谈到性能,是分析代码,这样你就不必去猜测一个好主意。

下面是一个简单的测试情况下解决此示例:

http://jsperf.com/most-performant-way-to-append-to-dom-elements

(以及相关小提琴演示的这个可视侧:http://jsfiddle.net/f62ptjbf/

该试验比较了这样四种可能的方法:(绝不掩盖所有解决方案)

  1. 追加“通过”作为文本节点(如您的示例代码)
  2. 追加“传递”为SPAN节点(稍有改变你的例子)
  3. 建设呈现节点和记录“通过”一个DOM片段,然后添加到DOM从HTML字符串中的一个附加操作
  4. 从DOM中删除selection元素,操作它们,然后重新添加到DOM。

这表明[至少在我的Chrome浏览器中]最快的方法是在处理之前删除元素,然后在处理后重新添加到DOM。(#4)

这是另一个测试,显示[至少在我的Chrome浏览器中]将SPAN元素附加文本“传递”比追加文本节点更快。

http://jsperf.com/append-variations

基于这些发现,我可以推荐两个潜在的性能改进代码:

  1. selection删除DOM元素操纵在他们面前,并在完成后重新添加。
  2. 附加SPAN与文本“传递”,而不是直接附加文本。

但是,如果元素具有共享父级,#1效果最好。性能将是append操作的数量的函数。