【问题标题】:jQuery selector performancejQuery 选择器性能
【发布时间】:2010-11-27 12:33:57
【问题描述】:

根据我如何表达我的选择器,我的性能会有很大差异。例如,看看这 2 个选择器,它们选择完全相同的元素:

A) someTableRow.find("td.someColumnClass").find("span.editMode").find("input")
B) someTableRow.find("td.someColumnClass span.editMode input")

我希望 B) 更快,因为只有 1 个调用,但实际上我发现 A) 的执行速度快了大约 8 倍。我不知道为什么,有人有任何见解吗?谢谢

【问题讨论】:

    标签: jquery performance css-selectors


    【解决方案1】:

    假设您至少使用 jQuery 1.3(即添加了 Sizzle),您看到的性能是由于遍历 DOM 的变化。来自here

    直到并包括 jQuery 1.2.6 选择器引擎以“自上而下”的方式工作 (或“从左到右”)方式。 jQuery 1.3.x(即,jQuery 嵌入的Sizzle)引入了“自下而上”(或 "从右到左") 查询方法 DOM。

    在您的第二个示例 ("td.someColumnClass span.editMode input") 中,Sizzle 有效地做到了这一点:

    1. 获取someTableRow中的所有input元素
    2. 对于找到的每个input 元素,使用class="editMode" 遍历其祖先树以查找span 元素。删除没有这些祖先的 input 元素
    3. 对于找到的每个span.editMode 元素,遍历其祖先树以查找具有class="someColumnClass"td 元素。删除没有这些祖先的 input 元素

    然而,在您的第一个示例中,您通过每次调用 find() 明确限定每个步骤,定义上下文并从那里遍历 down。您正在执行“自上而下”的方法。相当于每一步都传入一个上下文,即generally considered a performance booster

    $('input', $('span.editMode', $('td.someColumnClass', someTableRow)))
    

    【讨论】:

    • 感谢 crescentfresh,有道理。我们实际上刚刚从 1.2.6 迁移到 1.3.2,我很困惑为什么一些以前相当快速的选择器变得更慢(大多数更快)。问题 - 哪个更快,在每个点传递上下文,还是使用链式 find() 调用?
    • 它们实际上是等效的。 $('foo', 'bar') 实际上被重新路由到 jQuery 腹部的 $('bar').find('foo') 。我想调用 find() 显式节省了几个 CPU 周期,但没有什么可眨眼的。做任何对你的团队来说最易读的事情。我觉得非常易读 ;)
    • 酷,我觉得 find() 对我来说更直观,所以会使用它
    【解决方案2】:

    因为您正在减少搜索的上下文。

    在情况 B 中,它必须搜索每个 DOM 元素以查看它是否符合条件。

    如果 A 可以快速决定忽略任何不是“td.someColumnClass”的内容,那么它可以获取 DOM 的子集并忽略不在“span.editMode”中的任何内容。因此,它现在有一组更小的元素可供搜索以查找“输入”。

    【讨论】:

    • 如何在不遍历 someTableRow 的整个 DOM 子节点的情况下“快速决定忽略...”?它们都检查相同的完整子元素集,一个使用 someColumnClass 查找 td,然后使用 editMode 解析该列表以查找跨度,然后解析该列表以获取输入。另一个在初始列表的同一搜索中查找所有三个条件。
    • 由于这两个选择器的含义相同,我不明白为什么 jQuery 不能在两种情况下使用相同的策略。
    【解决方案3】:

    A 是更多的调用,但更简单。 B 是一个调用,但更复杂。在这种情况下,调用的复杂性大大超过了调用的数量。

    【讨论】:

      【解决方案4】:

      根据我的经验,JQuery 处理选择器的方式与 CSS 有点不同。

      正如 Josh 指出的那样,减少搜索的上下文是关键。

      我发现使用这两个参数选择器真的很快

      这在速度方面如何比较?

      这里不需要所有的变量,只是为了说明我在做什么。

      var columnClasses = $('.someColumnClass');
      var tableCell = $('td', columnclasses);
      var editMode = $('.editmode', tableCell);
      var spanInside = $('span', editMode);
      var inputFinally = $('input', spanInside);
      

      善良,

      【讨论】:

        【解决方案5】:

        我自己对 jQuery 选择器性能进行了一些研究。一个大问题是在 Internet Explorer 上按类名查找。 IE 不支持 getElementsByClassName - 因此 jQuery 和其他框架通过遍历所有 DOM 元素在 JavaScript 中“重新实现”它。 查看以下关于jQuery Selector Performance的分析博客

        【讨论】:

          【解决方案6】:

          这里有一篇关于选择器性能的非常有趣的文章:http://blogs.atlassian.com/developer/2009/08/jquery_bondage.html

          在其中,作者展示了一个“绑定”jQuery 扩展,显示函数被计算了多少次。

          【讨论】:

          • 提问者指的是find()的性能,而不是bind()
          猜你喜欢
          • 2011-06-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-08
          • 2012-05-15
          相关资源
          最近更新 更多