jQuery遍历是否优于选择器?

时间:2013-03-05 05:58:57

标签: javascript jquery performance

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

背景和我的想法:

我正在玩一个很好的互动try jQuery tutorial,其中一项任务是:

  

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

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

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

2 个答案:

答案 0 :(得分:21)

对此没有明确的答案,但对于您正在使用的:last选择器,它是Selectors API标准的专有扩展。因此,使用本机.querySelectorAll方法无效。

Sizzle的作用基本上是尝试将你的选择器与.querySelectorAll一起使用,如果由于选择器无效而抛出异常,它将默认为纯粹的基于JavaScript的DOM选择/过滤。

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

此外,还包括一些优化,以便当您的选择器非常简单时,例如ID或元素名称,将使用原生getElementByIdgetElementsByTagName,这非常快;通常甚至比querySelectorAll更快。

由于.last()方法只是抓取集合中的最后一项而不是过滤所有项目,这就是Sizzle过滤器通常做的(至少他们习惯),也会有所提升。

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


如果是$("#vacations").find("li"),请不要担心中期结果。这将使用getElementById后跟getElementsByTagName,并且速度非常快。

如果您真的非常关心速度,请减少对jQuery的使用,并直接使用DOM。


您目前会在:last等选择器的文档中找到备注,警告您性能损失:

  

因为:last是jQuery扩展而不是CSS规范的一部分,使用:last的查询无法利用本机DOM querySelectorAll()方法提供的性能提升。要在使用:last选择元素时获得最佳性能,请先使用纯CSS选择器选择元素,然后使用.filter(":last")

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

答案 1 :(得分:14)

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

Sizzle,jQuery的选择器引擎,使用正则表达式解析字符串,并尝试使用getElementByIdgetElementsByTagName来加速非常基本的选择器。如果您的选择器比#fooimg更复杂,它会尝试使用querySelectorAll,它只接受有效的CSS选择器(无:radio,{{1} },:eq或其他特定于jQuery的伪选择器。)

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

通过将选择器字符串分解为Sizzle可以快速解析的简单块(:checkbox#id),您基本上只是将对tagname和{{1}的调用链接在一起},这是你能得到的最快速度。