【问题标题】:Performance between doc.querySelectorAll('#id element') vs doc.querySelector('#id').querySelectorAll('element');doc.querySelectorAll('#id element') 与 doc.querySelector('#id').querySelectorAll('element'); 之间的性能
【发布时间】:2020-11-23 14:49:52
【问题描述】:

我正在尝试使用以下内容查找元素:

doc.querySelectorAll('#divContentList article');

效果很好,但另一位开发人员告诉我应该写:

doc.querySelector('#divContentList').querySelectorAll('article');

他说这样更好,因为它直接转到#divContentList,然后查找article 元素。

我不认为他的解决方案在速度性能方面是最好的,它会搜索元素两次。 我认为querySelectorAll 足以胜任它的工作。

主要问题是,哪一行代码总体上是最好的?

【问题讨论】:

  • 你们有没有测试过代码?
  • 你一定要测试一下,但是doc.querySelector('#divContentList')肯定会比#getElementById()慢。
  • 这几乎肯定不是您的应用程序中最慢的事情。别担心。
  • 为了它的价值,如果可能的话,我会使用getElementById。请参阅此测试用例:jsperf.com/selector-tests-jm

标签: javascript css-selectors selectors-api


【解决方案1】:

感谢Mauricio Soares 他的 jsPerf 第一个示例:

<div id="divContentList"> <article></article> </div>

确实是第一种方法:
doc.querySelectorAll('#divContentList article');
如果其中只有一个 article 会更快。

我已将 jsPerf 从 10 修改为 1000 article,性能差异很大。 Check it here

<div id="divContentList"> <article></article> ... <article></article> </div>

这将导致我的问题的第二种方法:
doc.querySelector('#divContentList').querySelectorAll('article');
速度更快

最后,使用getElementById 的性能略有提升。
doc.getElementById('divContentList').querySelectorAll('article');
那就是最好的表现

Keith Rousseau 正确,querySelectorAll 从右到左求值。

编辑

我还发现了 querySelectorgetElementById/getElementsByTagName 的不同之处。 querySelector 返回静态 NodeList,而 getElementById 返回 Live NodeList。

我又发了一个test
document.getElementById('divContentList').getElementsByTagName('article');
这个拿蛋糕。差别太可笑了

【讨论】:

  • 我用articles 更新了测试用例,这些测试用例不在#divContentList 中。如果 qsa 从右到左评估,我预计单个 qsa 会(非常)慢,但事实并非如此。我们该如何解释呢?
  • 不知道如何解释这个@Halcyon。我在 4 个月前听说浏览器从右到左读取 CSS。所以对于 qsa 来说,对我来说也是一个确认。这意味着您编写 CSS 的方式(从左到右思考)实际上是糟糕的 CSS,并且会对性能产生影响。所以拥有超过 2 个 CSS 选择器实际上很糟糕。或者定义html标签如section || .main .section 而不是 .main-section。让我觉得一个选择器可以统治所有这些。
【解决方案2】:

这个问题的答案是:

  • 方法 1 更快
  • 方法 2 更快
  • 没有区别

问题是答案可能会随着时间而改变。浏览器供应商倾向于优化经常使用的方法。如果经常使用方法 1,它可能会更快,或者将来会更快。

这两种方法似乎都和我一样(使用给定的输入)。如果有一个应该更快的根本原因:使用更快的方法。


由于您的第一个匹配项是 id,因此始终只能有一个匹配项。

如果您的查询是 ".parent .child",并且有许多没有孩子的父母,那么 ".parent .child"可能会比 (".parent").qsa(".child") 快。

【讨论】:

  • 这些方法似乎有区别。
  • 这个答案归结为“我不确定一种方法是否更快,但如果一种方法更快,那么你应该使用它。” - 这没什么帮助。
【解决方案3】:

querySelectorAll 从右到左求值,因此第一个将找到页面上的所有文章,然后将其过滤到仅位于 divContentList 下的文章。我会为 id 做 getElementById,然后在下面找到文章。

但正如其他人所说,测试它。并在多个浏览器中测试。

【讨论】:

    【解决方案4】:

    您可以使用 jsPerf 进行此类测试...

    我已经用你的用例here 设置了一个简单的性能测试,似乎它们具有相似的性能,“单一”的 querySelector 有时似乎更具性能,但我没有不要认为这在您的应用程序中会成为一个问题。

    【讨论】:

    • 您好,感谢您提供的链接。你真棒!这将意味着存在差异。编写第一种方法小于第二种方法。在这种情况下使用#idtagname
    • 是的,这可能会根据选择器的复杂性以及 DOM 中有多少元素而改变。 :)
    【解决方案5】:

    当然,这是一个古老的问题,但偶然发现了这个问题并想参与其中。提前一个重要的提示,我认为其他人没有深入研究过:这两个陈述不是 技术上的同义词。这可以解释一般的性能差异。

    这方面最简单的例子实际上是 YouTube。如果你去看任何视频,你会发现他们实际上重复了 ID,#content。在我尝试的第一个视频中,加载 cmets 部分后,document.querySelectorAll("#content") 实际上返回了大约 20 个元素。这不符合标准,W3's HTML Validator 实际上会告诉您这是无效的 HTML。但是,浏览器仍然允许这样做,而不是直接拒绝或修改 HTML。

    如果您的网站重复使用了#divContentList,您的语句将返回所有文章元素中的所有文章元素;而您的同事只会返回嵌套在它找到的 #divContentListfirst 实例中的文章。这可以解释为什么您的同事通常看起来更快(见下文)。正如大多数人已经指出的那样,将他/她的第一个 querySelector 替换为 getElementById 在所有浏览器中可能会更快。


    除此之外,我同意“如果您想知道某物的性能:只需测量它”这一普遍观点。但要小心你如何构建你的测试。 Here's an example where the JS engine optimized out the actual test case。我的建议始终是在您的实际用例的上下文中进行测试。有线程在谈论如何element.querySelectorcan actually be slower thandocument.querySelector;但是,从最近的简短测试来看,我无法复制这一点。

    在此页面本身上使用#sidebar.question-hyperlink 等ID/类,在所有情况下document.querySelector('&lt;ID&gt;').querySelectorAll('&lt;CLASS&gt;'); 的性能都优于document.querySelectorAll('&lt;ID&gt; &lt;CLASS&gt;');

    但是,我觉得这很关键,差异从未超过 ~10-20%。在某个时刻,问题变成了“是否值得在可读性/可写性与性能之间进行权衡”。如果您只运行此语句一到两次,差异可能以微秒为单位。对于一般用例,您的原始陈述或您同事的陈述都可以。

    最后一点,

    我不认为他的解决方案在速度性能方面是最好的,它会搜索元素两次

    如果您喜欢阅读,您可以了解浏览器实际上是如何为网页实现这些查找方法的。查看 Firefox 源代码,您会发现“getElementById”使用哈希表查找,这使得查找结果几乎是即时的。不同供应商的实施会有所不同,这就是为什么在许多不同的浏览器上测试您的网站很重要的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-06
      • 2023-03-20
      • 1970-01-01
      • 2020-03-24
      • 1970-01-01
      • 2012-05-04
      • 1970-01-01
      • 2010-12-12
      相关资源
      最近更新 更多