简体   繁体   English

获得dom元素的最快方法是什么?

[英]What is the fastest way to get a dom element?

I'm performance-tuning my code, and am surprised to find that the bottleneck is not dom node insert, but selection. 我正在对我的代码进行性能调优,并且惊讶地发现瓶颈不是dom节点插入,而是选择。

This is fast: 这很快:

var row = jquery(rowHTML).appendTo(oThis.parentTable);

but the subsequent getting of an element inside "row" is slow: 但随后在“行”中获取元素的速度很慢:

var checkbox = jquery(".checkbox input", row);

I need to get the checkbox in every row so I can attach an event handler to it. 我需要在每一行中获取复选框,以便我可以附加一个事件处理程序。 Selecting the checkbox is ALMOST 10X AS SLOW as inserting the entire parent row. 选择该复选框是ALMOST 10X AS SLOW,因为插入整个父行。

What am I doing wrong here? 我在这做错了什么?

DOM manipulation uses native functions to perform simple operations. DOM操作使用本机函数来执行简单操作。 Browser vendors optimize these. 浏览器厂商优化这些。 You are building the row from HTML. 您正在从HTML构建行。 Internally jQuery is using .innerHTML to build the collection which then patches into the browser's mega-fast parser. 在内部,jQuery使用.innerHTML来构建集合,然后将其修补到浏览器的超快速解析器中。

Selection is slow in comparison because JS code needs to loop through the DOM repeatedly. 选择比较慢,因为JS代码需要重复遍历DOM。 Newer browsers have native selection handling which provides dramatic speedups to selector based JS. 较新的浏览器具有本机选择处理功能,可为基于选择器的JS提供显着的加速。 As time moves on this will be less of a problem. 随着时间的推移,这将不再是一个问题。

Here is how the query in question, $(".checkbox input", row) , breaks down: 以下是有问题的查询$(".checkbox input", row) ,如何分解:

  1. row.getElementsByTagName('*');
  2. for-loop through every element returned (all elements within the row) and test elements[i].className with /(\\s|^)checkbox(\\s|$)/ . for循环遍历返回的每个元素(行中的所有元素)和测试elements[i].className/(\\s|^)checkbox(\\s|$)/
  3. for-loop every element still remaining and collect matched[i].getElementsByTagName('input'); for循环每个元素仍然存在并收集matched[i].getElementsByTagName('input');
  4. unique the final collection. 独特的最终系列。

This is different for jQuery 1.3 as it's engine moves through the selector the other way around, beginning with getting all input elements and then testing the parent elements. 这与jQuery 1.3不同,因为它的引擎以相反的方式通过选择器,从获取所有输入元素然后测试父元素开始。

Rremember that the JS selector engines implement a lot more of the CSS selector spec than is actually usable with CSS (or implemented by current browsers). Rremember认为JS选择器引擎实现了很多CSS选择器规范,而不是实际可用于CSS(或由当前浏览器实现)。 Exploiting this, and knowledge of the engines, we can optimize selector can be optimized in a few different ways: 利用这一点,以及对引擎的了解,我们可以通过几种不同的方式优化选择器:

If you know what element type the .checkbox is: 如果你知道.checkbox是什么元素类型:

$("td.checkbox input", row);

It is faster for filter first for type and then for the class for only those matches. 首先对类型进行过滤,然后对于仅对那些匹配进行类更快。 This doesn't apply for a very small subset of elements, but that is almost never the case in praxis. 这不适用于非常小的元素子集,但在实践中几乎不是这种情况。

The single class test is the slowest of the common selectors people actually use . 单一类测试是人们实际使用的常见选择器中最慢的。

Simpler selection: 更简单的选择:

$("input[type=checkbox]", row);

One loop is faster than two loops. 一个循环比两个循环快。 This only finds input elements and then directly filters them by type attribute. 这只找到输入元素,然后直接按类型属性过滤它们。 Since sub/child-elements are never used, unique may also be skipped (and smart engines will try to do this because unique is slow). 由于从不使用sub / child-elements,因此也可以跳过unique(并且智能引擎会尝试执行此操作,因为unique很慢)。

A more direct selector: 更直接的选择器:

$("td:first.checkbox input", row);

A more complex selector may actually be faster if it is more direct (YMMV). 如果更直接(YMMV),更复杂的选择器实际上可能更快。

If possible, move the search context up to the table level: 如果可能,将搜索上下文移动到表级别:

By this I mean that instead of looping through the rows, and searching for the checkbox in every one, leave them alone until after the loop and then select them all at a time: 我的意思是,不是循环遍历行,而是在每个行中搜索复选框,而是将它们留在循环之后,然后一次全部选择它们:

$("tr td:first.checkbox input", table);

The point of this is to eliminate the overhead of firing the selector engine up repeatedly, but instead do everything in one haul. 这样做的目的是消除重复启动选择器引擎的开销,而是一次性完成所有操作。 This is presented here for completeness rather than something that I think would return massive speedups. 这里提供的是完整性,而不是我认为会带来大量加速的东西。

Don't select: 不要选择:

Build the row from bits, assigning events as you go. 从位构建行,随时分配事件。

var row = $( '<tr></tr>' );
var cell = $( '<td class="checkbox"></td>' ).appendTo( row );
$( '<input type="checkbox" name="..."/>' ).appendTo( cell ).click(/* ... */);

This may be impossible for reasons of Ajax or other templates out of your control. 由于Ajax或其他模板无法控制,这可能是不可能的。 Additionally, the speed may not be worth turning your code into this sort of mess, but sometimes this may make sense. 此外,速度可能不值得将您的代码变成这种混乱,但有时这可能是有道理的。

Or, if none of these work for you, or return too performance gain, it may be time to rethink the method entirely. 或者,如果这些都不适合您,或者返回太多的性能增益,那么可能是时候重新考虑该方法了。 You can assign an event listener higher up the tree and grab the events there, instead of per-element instance: 您可以在树的上方分配一个事件侦听器并在那里获取事件,而不是每个元素实例:

$('table').change(function(e){
  // you may want a faster check...
  if ( $(e.target).is('input[type=checkbox]') ) {
    // do some stuff ...
  }
});

This way you don't do anything unless, and until, the user actually requests it. 这样,除非用户实际请求,否则您不会执行任何操作。 Fastest. 最快的。 :-) :-)

var checkbox = jquery(".checkbox input", row);

This is traversing the entire dom tree to find the checkbox. 这是遍历整个dom树以找到复选框。 You could possibly speed it up by changing the selector to an ID which can use the browsers native getElementById functionality. 您可以通过将选择器更改为可以使用浏览器本机getElementById功能的ID来加快速度。

var checkbox = jquery("#checkbox input", row);

You could also use your row as a starting point for the DOM search like the following example. 您还可以使用行作为DOM搜索的起点,如下例所示。 Now your not parsing through the entire DOM tree again to find the matched element. 现在你不再遍历整个DOM树来查找匹配的元素。

var row = jquery(rowHTML).appendTo(oThis.parentTable);
row.children(".checkbox input");

Use event delegation and add a single handler to a parent element and not the checkboxes themselves. 使用事件委托并将单个处理程序添加到父元素,而不是复选框本身。

jQuery supports this via the live() function. jQuery通过live()函数支持这个。

Try putting a class name on the input field itself. 尝试在输入字段上放置一个类名。 That may prove to be faster. 这可能会更快。

The reason for that is your code goes through all .checkbox classes, tries to find the input child of that element and returns that. 原因是你的代码遍历所有.checkbox类,试图找到该元素的输入子元素并返回它。 I think that action might be your culprit. 我认为这个行动可能是你的罪魁祸首。

By simply just looking for all elements with the class the input field has, you might see some speedup. 通过简单地只查找输入字段所具有的类的所有元素,您可能会看到一些加速。

尝试使用Sly ,它强调性能。

获取DOM元素的最快方法是使用纯JavaScript并通过ID调用它。

var element = document.getElementById('element);

If you're looking for performance, jQuery selectors are very slow. 如果你正在寻找性能,jQuery选择器非常慢。 In the example there, it has to scan the full DOM tree and check CSS classes and so on to find the relevant nodes. 在那里的例子中,它必须扫描完整的DOM树并检查CSS类等,以找到相关的节点。

It is significantly faster to use native DOM methods. 使用本机DOM方法要快得多。 There are some interesting library performance comparisons here: 这里有一些有趣的库性能比较:

http://ajaxian.com/archives/taskspeed-more-benchmarks-for-the-libraries-and-browsers http://ajaxian.com/archives/taskspeed-more-benchmarks-for-the-libraries-and-browsers

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM