jQuery 选择器的性能

Performance of jQuery selector

这个选择器是:

$("div#myId")

比这个选择器更快:

$("#myId")

? 两者都很好,但我想提高性能。

根据 jsperf$("#myId")$("div#myId").

~4 倍

使用 id 值时,您添加到选择器的任何其他内容都不会提高性能。浏览器已经有了所有 id 值的索引,因为文档中的所有 id 都应该是唯一的。向选择器添加其他东西只会使它必须测试的东西更多。例如,对于 #myId,可以使用对 document.getElementById("myId") 的短路,但在 div#myId、jQuery 或其调用的函数必须首先将选择器解析为它的件,找到具有正确 ID 的对象,然后检查它是否也是 div.

如果你真的想绝对确定地知道任何两种情况之间的性能差异,那么你必须编写性能测试(在像 http://jsperf.com 这样的工具中并在所有相关浏览器中测试它。

一般来说,您应该遵循使用最简单的代码以适当的性能完成工作的公理。那可能是 $("#myId") 除非你真的想优化纯性能,在这种情况下你会使用 document.getElementById("myId").

而且,对于 grins,jQuery 根本不快(它创建一个对象,运行s 一个构造函数,分析选择器,评估选择器,查看其他可能的选项passed, etc...), 所以如果你真的关心优化最大化性能,你就不会首先使用 jQuery 。也就是说,jQuery 大大加快了编写代码的时间,因此在很多情况下都是值得的。

请参阅 jsperf:http://jsperf.com/jqvsother 进行性能比较。

在Chrome中,三者的区别还是挺大的:

$("div#myId")                    -    446,589 ops/sec
$("#myId")                       -  1,705,994 ops/sec
document.getElementById("myId")  - 32,278,617 ops/sec

因此,$("#myId")$("div#myId") 快 4 倍,document.getElementById("myId")$("#myId") 快 19 倍。这是一个比我预期的更大的差异。

这是一个图形表示(长条更快):

当你测量而不是猜测时,你总能学到一些东西。


深入研究 jQuery 选择器处理代码,您会看到:

  1. 检查是否传递了任何选择器。
  2. 检查它是否是一个字符串,是否看起来像 HTML "<.....>"
  3. 如果看起来不像简单的 HTML,运行 这个 /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/ 正则表达式就可以了
  4. 如果正则表达式显示选择器只是 "#xxxx",则调用 document.getElementById()
  5. 如果它看起来更复杂 HTML(可能带有属性),则将 HTML 处理成 DOM 个对象
  6. 如果没有这些特殊字符串中的任何一个,则运行 .find() 找到匹配的选择器。 运行 .find() 将选择器从要评估的 Sizzle 引擎传递出去(从头开始)。
  7. Sizzle 引擎然后 运行 选择器上的另一个正则表达式,再次寻找它可以选择更快方法的快捷方式。
  8. 最终,如果 none 的快捷方式通过并且选择器中没有特殊项目,则调用 querySelectorAll()
  9. 等等,处理其他可能要传递的非字符串的东西(DOM对象,jQuery对象等...)

所以,我从中得到了一些东西。首先,有一个简单的“#xxxx”字符串的快捷方式,可以避免很多其他处理。为什么这样更快也就不足为奇了。其次,任何避免进入最终调用 querySelectorAll() 的 Sizzle 选择器评估代码深处的捷径都会加快速度。

基于 http://learn.jquery.com/performance/optimize-selectors/#specificity 很高兴注意到 jQuery 从右到左读取选择器。

意味着如果你要写这样的东西 $("div#myId") jQuery 将获取所有元素,匹配具有相同 ID 的元素(因为 ID 是唯一的,它应该停在这里)但是因为你还指定 div,jQuery 将继续并检查它是否是 div。这将使一项额外的工作成为不必要的。

因此,对于其他选择器,最好注意右侧比左侧更具体。

切勿在 id 之前添加标签名称,这会降低选择器的速度。 $('#content') 优于 $('div#content')

jQuery 开始使用正则表达式解析选择器。如果它透露选择器是一个 id,因为它以一个尖锐的 (#) 开头,在幕后 jQuery 将使用 JavaScript 原生的 getElementById() 方法,那是非常快的。