注意: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:感谢你帮助我们保持警觉 – 我们期待着看到你的库改进,以及每个人都获益。