【问题标题】:What is the fastest way to get a dom element?获取 dom 元素的最快方法是什么?
【发布时间】:2009-04-03 15:13:01
【问题描述】:

我正在调整我的代码的性能,并且惊讶地发现瓶颈不是 dom 节点插入,而是选择。

这很快:

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

但是随后在“行”中获取元素的速度很慢:

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

我需要在每一行中获取复选框,以便我可以将事件处理程序附加到它。选中该复选框几乎是插入整个父行的 10 倍。

我在这里做错了什么?

【问题讨论】:

  • 嗯。这很奇怪。两个人给了我一个可行的解决方案,但随后他们的帖子消失了。无论如何,似乎从选择器中删除类名会大大加快速度。 Christoph 的回答是,使用事件委托对我来说实际上看起来最好,但变化更大。

标签: javascript jquery dom


【解决方案1】:

DOM 操作使用本地函数来执行简单的操作。浏览器供应商优化这些。您正在从 HTML 构建行。 jQuery 在内部使用 .innerHTML 构建集合,然后将其修补到浏览器的超高速解析器中。

选择比较慢,因为 JS 代码需要反复循环遍历 DOM。较新的浏览器具有本机选择处理,这为基于选择器的 JS 提供了显着的加速。随着时间的推移,这将不再是一个问题。

下面是相关查询 $(".checkbox input", row) 的分解方式:

  1. row.getElementsByTagName('*');
  2. for 循环遍历返回的每个元素(行内的所有元素)并使用 /(\s|^)checkbox(\s|$)/ 测试 elements[i].className
  3. for-loop 剩余的每个元素并收集matched[i].getElementsByTagName('input');
  4. 独特的最终集合。

这与 jQuery 1.3 不同,因为它的引擎以相反的方式在选择器中移动,从获取所有输入元素开始,然后测试父元素。

请记住,JS 选择器引擎实现的 CSS 选择器规范比实际可用于 CSS(或由当前浏览器实现)的要多得多。利用这一点以及对引擎的了解,我们可以优化选择器,可以通过几种不同的方式进行优化:

如果您知道.checkbox 是什么元素类型:

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

先过滤类型,然后过滤类,只过滤那些匹配项会更快。这不适用于非常小的元素子集,但在实践中几乎从未如此。

单类测试是最慢的常见selectors people actually use

更简单的选择:

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

一个循环比两个循环快。这只会找到输入元素,然后直接按类型属性过滤它们。由于从不使用子/子元素,因此也可能会跳过唯一性(智能引擎会尝试这样做,因为唯一性很慢)。

更直接的选择器:

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

如果更直接 (YMMV),更复杂的选择器实际上可能会更快。

如果可能,将搜索上下文移至表格级别:

我的意思是,与其循环遍历行,并在每一行中搜索复选框,不如将它们单独放置,直到循环结束,然后一次选择它们:

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

这样做的目的是消除重复启动选择器引擎的开销,而是一次完成所有事情。这是为了完整性,而不是我认为会带来巨大加速的东西。

不要选择:

从位构建行,随时分配事件。

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

由于 Ajax 或您无法控制的其他模板,这可能是不可能的。此外,速度可能不值得将您的代码变成这种混乱,但有时这可能是有道理的。

或者,如果这些都不适合您,或者返回的性能提升太大,那么可能是时候重新考虑该方法了。您可以在树的上方分配一个事件侦听器并在那里获取事件,而不是每个元素的实例:

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

这样,除非用户实际请求,否则您不会做任何事情。最快的。 :-)

【讨论】:

  • 哇。长,很好的答案。我需要一分钟来消化这个。谢谢博格!
  • 我碰巧写了一个选择器引擎,所以这是一个我碰巧知道一些事情的领域。 :-)
  • 感谢您的深入解释
【解决方案2】:
var checkbox = jquery(".checkbox input", row);

这是遍历整个 dom 树来找到复选框。您可以通过将选择器更改为可以使用浏览器原生 getElementById 功能的 ID 来加快速度。

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

您也可以使用您的行作为 DOM 搜索的起点,如下例所示。现在您无需再次解析整个 DOM 树来查找匹配的元素。

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

【讨论】:

  • re:遍历整个DOM树——这不是只遍历“row”的子节点吗?
  • 我认为添加第二个“row”参数会阻止 jquery 遍历整个 dom 树,并使其仅从我的 row 元素开始。我弄错了吗?
  • 嗯,你对的 morgancodes,我要做一些测试。您主要使用表格行还是 div?
  • 使用“#checkbox input”作为选择器有点矫枉过正——“#checkbox”肯定会识别单个元素,因此需要检查“input”是完全多余的吗?
【解决方案3】:

使用事件委托并将单个处理程序添加到父元素而不是复选框本身。

jQuery 通过live() 函数支持这一点。

【讨论】:

  • 好主意。我从来没有想过以这种方式处理事件。
  • @morgancodes:我开始将事件委托几乎专门用于冒泡事件,并将大多数侦听器添加到文档(事件层次结构的根);它可能效率低下(无论事件源如何,所有侦听器都会触发),但它非常方便,例如不需要 onload hacks
【解决方案4】:

尝试将类名放在输入字段本身上。这可能会更快。

原因是您的代码遍历所有 .checkbox 类,试图找到该元素的输入子元素并返回它。我认为那个动作可能是你的罪魁祸首。

通过简单地查找输入字段具有的类的所有元素,您可能会看到一些加速。

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 我不知道,我个人不会相信 9 年前所说的 DOM 性能 :)
    【解决方案6】:

    如果您正在寻找性能,jQuery 选择器非常慢。在那里的示例中,它必须扫描完整的 DOM 树并检查 CSS 类等以找到相关节点。

    使用原生 DOM 方法明显更快。这里有一些有趣的库性能比较:

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

    【讨论】:

      【解决方案7】:

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

      var element = document.getElementById('element);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-05-17
        • 1970-01-01
        • 2012-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多