哪种jQuery选择方法更快?

6
我想知道使用jQuery的上下文参数与使用普通CSS作用域选择器相比是否有优势。
假设我有以下HTML代码:
<div class="contacts">
    <h1>All contacts</h1>
    <div class="contact new">
        <p class="name">Jim Jones</p>
        <p class="phone">(555) 555-1212</p>
    </div>
    <div class="contact new">
        <p class="name">Bob Smith</p>
        <p class="phone">(555) 555-1213</p>
    </div>
    <div class="contact new">
        <p class="name">Dave Baker</p>
        <p class="phone">(555) 555-1214</p>
    </div>
    <div class="contact">
        <p class="name">Pete Harrison</p>
        <p class="phone">(555) 555-1215</p>
    </div>
    <div class="contact">
        <p class="name">George Donald</p>
        <p class="phone">(555) 555-1216</p>
    </div>
    <div class="contact">
        <p class="name">Chris Root</p>
        <p class="phone">(555) 555-1217</p>
    </div>
</div>

如果我想从联系人 div 中获取所有新的联系人(标记为 'new' 类),哪种方法更快、更可扩展等等?

$('.contacts .new');

或者

$('.new', '.contacts');

jsFiddle

更新

答案和评论中有很多很棒的信息。总结一下主要观点,在大多数浏览器中,当有多个 .contacts divs 时,单个选择器能够更好地扩展。在只有一个 .contacts div 存在时,两个选择器的上下文方法更快。

从中可以得到一些有用的启示,我们可以在选择带有 id 的元素内进行选择时使用一种方法。

$('p:first', '#chapter2'); // get the first paragraph from chapter 2

当我们需要从可能包含大量元素的组中进行选择时,请使用单个选择器方法。

$('.chapter p:first-child'); // get the first paragraph from all chapters

当你测试它们时,你发现了什么? - user113716
有时候问一下会更容易,而且你可能会得到更多的信息。例如,在这里我了解到了jsperf的存在。 :) - Craig M
6个回答

11

尽管一切都看起来不太可能,但似乎第二个选项是最快的。

在这里查看


3
我对这个问题的看法是:jQuery 可以检测到每个选择器都是一个简单的类查找,因此将两者委托给高度优化的浏览器函数 getElementsByClassName。当它们在一个字符串中时,它无法进行这样的优化,并且会使用 querySelectorAll 或其自己的方法来查找它。 - nickf
5
我刚在Opera浏览器中运行了它,请查看结果。这已经是我运行的第三个测试,表明他们对querySelectorAll进行了极其优化。 - user113716
@nickf 我想这是有道理的。顺便说一下:Firefox 6比Firefox 5更快。但是使用这两个选择器时,Firefox 5和Firefox 6之间存在巨大差异。 - Matt
哇,这太疯狂了。我刚刚尝试使用自己的jsPerf测试,使用了“jquery-selection-method”作为标识符,结果被告知该标识符已经被使用了。 - Dan Tao
1
谢谢,Pablo!这正是我需要的信息。在此过程中,感谢你让我了解jsPerf。 - Craig M
显示剩余11条评论

1

第二个是未记录的,所以你根本不应该使用它。

context参数应该是:

用作上下文的DOM元素、文档或jQuery对象

参考:http://api.jquery.com/jQuery/

字符串都不是这些东西。

因此,在将其用作上下文之前,您应该从选择器创建一个jQuery对象:

$('.new', $('.contacts'));

由于您正在进行两个jQuery调用,因此速度应该会稍慢一些。但是,这两个表达式基本上执行相同的工作,因此差异不应该太大。

编辑:

测试方法的扩展性:http://jsperf.com/jquery-selection-method/4

显示性能在不同浏览器之间有所不同。当您只有一个.contacts时,单个选择器在大多数浏览器中都会比较慢,除了Opera,它非常快。对于多个.contacts元素,单个选择器的扩展性更好。


很好,我在Pablo的帖子中添加了那个测试用例,现在更符合它应该有的样子。所以这确实表明它现在正在使用getElementByClassName,这比queryall更快。 - Matt
1
你的可扩展性测试似乎有些无意义,因为如果只有一个.contacts元素,使用ID会是更好的选择(例如$('#contacts')中的$('.new')),并且速度应该更快。如果有多个.contacts元素,则第二种方法可能不太适用于大规模。 - Andy E
1
@Andy E:你说得有道理。我编辑了测试,加入了多个.contacts元素,而单一选择器可以更好地处理它们。 - Guffa

1
在你的两个例子中,第一个选择器可能会更快。然而,如果你将上下文分配给一个变量,然后使用第二种方法,它会快得多。
contacts = $('div.contacts');
$('.new', contacts);

您可以在http://jsperf.com/jquery-context-with-tagname上查看结果。如果您有一个更大的HTML文档,则使用标签名称作为前缀也可能会提高性能。

1

$('.contacts .new') 理论上应该更具可扩展性,因为它仅对选择器引擎进行一次调用。而对于 $('.new', '.contacts'),最少需要进行两次选择器函数调用 —— 首先要获取所有类名为 .contacts 的元素,然后针对每个返回的 .contacts 元素再进行进一步的调用。

简而言之,当在 HTML 中添加更多的 .contacts 元素时,第二种方法就需要进行循环,并且速度会明显变慢。如果不打算使用更多的 .contact 元素,则应该使用 ID,这样会更快。


1

http://jsfiddle.net/cvWA7/1/

我得到的结果是,第一个选择器$('.contacts .new')大约快了22%。

更新有趣的是Pablo得到了相反的结果。我想知道我的测试是否有问题。

更新2这是在Chrome 13上运行的。


1
性能因测试浏览器的不同而有很大差异。例如,单个选择器在Opera中快了约200%。 - Guffa

1

据我所知,$('.foo', '.bar') 委托给 $('.bar').find('.foo'),因此第二个应该更快。

$('.foo', '.bar')$('.foo .bar') 更快的原因是因为它被 Sizzle 作为本地的 getElementsByClassName 执行。在代码的早期阶段,会检查只包含单个类名的选择器,而不执行任何复杂的逻辑。

更新:像我想的那样,使用 find() 稍微更快一些:http://jsperf.com/jquery-selection-method/2

更新2:我在 jQuery 的代码中查找了一下 - $('.foo', '.bar') 确实委托给了 $('.bar').find('.foo') - https://github.com/jquery/jquery/blob/master/src/core.js#L171


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接