我正在对我的代码进行性能调优,并且惊讶地发现瓶颈不是dom节点插入,而是选择.
这很快:
var row = jquery(rowHTML).appendTo(oThis.parentTable);
但随后在"行"中获取元素的速度很慢:
var checkbox = jquery(".checkbox input", row);
我需要在每一行中获取复选框,以便我可以附加一个事件处理程序.选择该复选框是ALMOST 10X AS SLOW,因为插入整个父行.
我在这做错了什么?
DOM操作使用本机函数来执行简单操作.浏览器厂商优化这些.您正在从HTML构建行.在内部,jQuery .innerHTML
用于构建集合,然后将其修补到浏览器的超快速解析器中.
选择比较慢,因为JS代码需要重复遍历DOM.较新的浏览器具有本机选择处理功能,可为基于选择器的JS提供显着的加速.随着时间的推移,这将不再是一个问题.
以下是有问题的查询如何$(".checkbox input", row)
分解:
row.getElementsByTagName('*');
for循环遍历返回的每个元素(行中的所有元素)并elements[i].className
使用/(\s|^)checkbox(\s|$)/
.
for循环每个元素仍然存在并收集 matched[i].getElementsByTagName('input');
独特的最终系列.
这与jQuery 1.3不同,因为它的引擎以相反的方式通过选择器,从获取所有输入元素然后测试父元素开始.
Rremember认为JS选择器引擎实现了很多CSS选择器规范,而不是实际可用于CSS(或由当前浏览器实现).利用这一点,以及对引擎的了解,我们可以通过几种不同的方式优化选择器:
如果你知道它是什么元素类型.checkbox
:
$("td.checkbox input", row);
首先对类型进行过滤,然后对于仅对那些匹配进行类更快.这不适用于非常小的元素子集,但在实践中几乎不是这种情况.
单一类测试是人们实际使用的常见选择器中最慢的.
更简单的选择:
$("input[type=checkbox]", row);
一个循环比两个循环快.这只找到输入元素,然后直接按类型属性过滤它们.由于从不使用sub/child-elements,因此也可以跳过unique(并且智能引擎会尝试执行此操作,因为unique很慢).
更直接的选择器:
$("td:first.checkbox input", row);
如果更直接(YMMV),更复杂的选择器实际上可能更快.
如果可能,将搜索上下文移动到表级别:
我的意思是,不是循环遍历行,而是搜索每个行中的复选框,不要将它们留在循环之后,然后一次选择它们:
$("tr td:first.checkbox input", table);
这样做的目的是消除重复启动选择器引擎的开销,而是一次性完成所有操作.这里提供的是完整性,而不是我认为会带来大量加速的东西.
不要选择:
从位构建行,随时分配事件.
var row = $( '' ); var cell = $( ' ' ).appendTo( row ); $( '' ).appendTo( cell ).click(/* ... */);
由于Ajax或其他模板无法控制,这可能是不可能的.此外,速度可能不值得将您的代码变成这种混乱,但有时这可能是有道理的.
或者,如果这些都不适合您,或者返回太多的性能增益,那么可能是时候重新考虑该方法了.您可以在树的上方分配一个事件侦听器并在那里获取事件,而不是每个元素实例:
$('table').change(function(e){ // you may want a faster check... if ( $(e.target).is('input[type=checkbox]') ) { // do some stuff ... } });
这样,除非用户实际请求,否则您不会执行任何操作.最快的.:-)