47

使用$("#vacations").find("li").last()是比 更好的做法$("#vacations li:last")吗?

背景和我的想法:

我正在玩一个很好的交互式试用 jQuery 教程,其中一项任务说:

在查看代码时,您注意到其他人正在选择最后一个假期:$("#vacations li:last")。你看着这个,你会想,“遍历会让这条路更快!” 您应该根据这些想法采取行动,重构此代码以使用遍历找到 #vacations 中的最后一个 li。

为什么我会这么认为?对我来说,选择器的使用看起来比遍历要高一些。在我看来,当我指定一个选择器时,jQuery 如何更好地获得我需要的单个结果(无需返回中间结果)。

使用复合选择器的额外开销是多少?是因为当前的选择器逻辑实现只是解析字符串并使用遍历 API?解析字符串这么慢吗?未来的实现是否有可能使用不需要返回中间结果并且比遍历更快的事实?

4

2 回答 2

21

对此没有直接的答案,但就:last您使用的选择器而言,它是 Selectors API 标准的专有扩展。.querySelectorAll因此,与本机方法一起使用是无效的。

Sizzle 所做的基本上是尝试将您的选择器与.querySelectorAll.

这意味着包括选择器之类的:last将导致您无法使用本机代码获得 DOM 选择的速度提升。

此外,还包含一些优化,因此当您的选择器非常简单时,例如只是一个 ID 或一个元素名称,将使用原生的getElementByIdgetElementsByTagName,这非常快;通常甚至比querySelectorAll.

而且由于该.last()方法只是抓取集合中的最后一个项目,而不是过滤所有项目,这是 Sizzle 过滤器通常所做的(至少他们曾经这样做过),这也将起到推动作用。

IMO,远离专有的东西。现在这.querySelectorAll几乎无处不在,只使用符合标准的选择器有真正的优势。做任何进一步的过滤后 DOM 选择。


在 的情况下$("#vacations").find("li"),不要担心中期结果。这将使用getElementById后跟getElementsByTagName,并且会非常快。

如果你真的超级在意速度,那就减少 jQuery 的使用,直接使用 DOM。


您目前会在文档中找到类似 选择器的注释,这些注释会:last警告您性能损失:

因为 :last 是一个 jQuery 扩展而不是 CSS 规范的一部分,所以使用的查询:last不能利用原生 DOMquerySelectorAll()方法提供的性能提升。要在使用:lastto 选择元素时获得最佳性能,首先使用纯 CSS 选择器选择元素,然后使用.filter(":last").

但我不同意这.filter(":last")将是一个很好的替代品。更好的是这样的方法.last()将直接针对元素而不是过滤集合。我有一种感觉,他们只是希望人们继续使用他们不符合标准的选择器。IMO,你最好忘记它们。

于 2013-03-05T06:25:09.740 回答
14

这是您的设置的测试:http: //jsperf.com/andrey-s-jquery-traversal

jQuery 的选择器引擎SizzlegetElementById使用正则表达式解析字符串,并尝试使用and来加速非常基本的选择器getElementsByTagName。如果您的选择器比#fooand更复杂img,它会尝试使用querySelectorAll,它只接受有效的 CSS 选择器(没有:radio,:eq:checkbox其他 jQuery 特定的伪选择器)。

选择器字符串可读性较差速度较慢,因此确实没有理由使用它。

通过将选择器字符串分解成 Sizzle 可以快速解析的简单块 ( #idand tagname),您基本上只是将对 and 的调用链接在一起getElementByIdgetElementsByTagName这几乎是您可以获得的最快速度。

于 2013-03-05T06:29:15.423 回答