注意:Jack 已经 修复了这篇文章中提到的几乎所有问题 - 干得漂亮!
我们一直在推迟谈论新的 1.1 版本中 jQuery 选择器的速度,直到我们的版本更接近发布 - 然而,似乎这个过程已经被 加速 了。所以既然已经公布了,让我们看看 jQuery 的选择器速度。
简而言之:对于 jQuery 1.1,我们付出了非常非常大的努力来使 它的选择器非常快。事实上,根据我们所有的测试,我们的速度比任何其他选择器库都快。在 1.1 版本的开发过程中,Dean Edwards 的 cssQuery 远远超过了任何其他选择器库。它非常全面,而且非常快。
今天,Jack Slocum 发布了他的新的 DOMQuery 选择器库。简而言之:标准已经被提高了。他的库非常非常快。可能是目前最快的库。
但是,在他库和我们库之间的比较中,出现了一些我们想要澄清的错误。(由 Jack 和 jQuery 双方造成的)(作为参考,这是我用于测试的 比较套件。)
jQuery 完全支持所有属性选择器。
例如,[@foo]、[@foo=bar] 等等。值得注意的差异是 jQuery 在这种情况下使用 XPath 风格的语法。由于 Jack 的测试没有考虑这一点,因此似乎我们在所有属性选择器测试中都失败了。
我们的“elem:empty” 工作正常。
您可以在 Jack 的测试中看到,所有选择器(除了 DOMQuery)都无法通过 :empty 测试 - 这是因为他在与 DOMQuery 进行比较,而 DOMQuery 的结果是错误的。规范规定,如果某个元素不包含任何子元素或文本节点,则它为空。在这种情况,似乎没有考虑到这一点。
[foo!=bar]、:first、:last 不是任何规范的一部分。
…但它们出现在测试套件中。顺便说一下,jQuery 确实实现了 :first 和 :last - 但没有实现 [foo!=bar](似乎只在 cssQuery 中?)。总的来说,当你设计的东西不是为了比较而设计时,与其他人进行比较是非常奇怪的。
span:not(span.hl-code) 匹配什么?
这是一个奇怪的灰色地带,我还没有看到任何地方对此进行讨论,规范也无法提供任何帮助。结果集应该是所有不具有 hl-code 类的 span - 还是什么都没有,因为你已经过滤掉了所有 span?例如
// Finds nothing in both
span:not(span)
=> []
// Finds spans that don't have a class of 'foo', in both
span:not(.foo)
=> [ <span>, <span>, ... ]
// jQuery's interpretation of the combination:
$("span:not(span.foo)")
=> []
// DOMQuery's interpretation of the combination:
Ext.select("span:not(span.foo")
=> [ <span>, <span>, ... ]
我们完全承认在这方面可能错了 - 但我很想知道其他人是怎么说的,以及他们对规范的解释是什么。
DOMQuery 没有考虑重复项。
目前,执行 Ext.select(“div div”) 返回的元素数量比只执行 Ext.select(“div”) 返回的要多 - 并且执行 Ext.select(“div div div”) 返回的元素集又有所不同,但仍然比只执行 Ext.select(“div”) 返回的多。事实上,考虑重复项是 JavaScript 选择器库中一个巨大的问题 - 而且目前,jQuery 是唯一一个正确解决这个问题的。
重点是,考虑重复项可能会非常昂贵(计算上) - 因此 DOMQuery 没有考虑重复项,给人一种速度提升的假象。例如
// DOMQuery
Ext.select("div").elements.length
=> 246
Ext.select("div div").elements.length
=> 624
Ext.select("div div div").elements.length
=> 523
// jQuery
jQuery("div").length
=> 246
jQuery("div div").length
=> 243
jQuery("div div div").length
=> 239
DOMQuery 不支持多个过滤器:elem.foo[foo=bar] 或 elem.foo.bar
在实现这一点之前,与任何其他库的比较都是不公平的。构建一个能够完全处理这些方面的库(例如:cssQuery、jQuery)需要付出巨大的代价。(无论是代码大小还是速度成本。)
DOMQuery 的 #id 选择器不检查上下文
你会注意到,如果你尝试执行以下查询:
Ext.select("div #badid").elements
=> [div#badid]
你会得到一个名为“badid”的元素 - 即使该元素实际上不在 div 内部。由于 DOMQuery 代码中没有进行有效性检查,所以它的速度非常快 - 而且非常错误。
我应该提到,在 1.1 之前,jQuery 在这一点上也是错误的,所以这是一个很容易被忽视的问题。
根元素去哪里了?
你会发现,在 DOMQuery 中搜索“html”和“*”奇怪地缺少了一些明显的东西:HTML 元素。似乎将根 DOM 元素从所有查询中排除有点奇怪;特别是因为这完全有效:“html > body *”。
......为了公平起见 - 这里有一个针对我们自己的 :-)
我们的 :nth-child(even/odd) 有缺陷。
目前,它似乎只选择一个元素 (!?)。我为此创建了一个 票证,它应该在周日的 1.1 版本中解决。
总的来说,看到 DOMQuery 在速度上取得的飞跃真是太棒了。选择器速度是一个真正需要竞争的领域;每当速度有所提高,每个人都将从中受益(用户、开发者 - 所有人)。
事实上,仔细研究了他的代码后,我已经有了更多关于如何提高 jQuery 速度的想法!
所以,对 Jack 来说:感谢你帮助我们保持警惕 - 我们期待着看到你的库改进,并让每个人都获益。