jquery 和 CSS 中最快的选择器方法 - ID 与否?

Posted

技术标签:

【中文标题】jquery 和 CSS 中最快的选择器方法 - ID 与否?【英文标题】:Fastest selector method in jquery and CSS - ID or not? 【发布时间】:2011-08-27 11:31:23 【问题描述】:

jquery/javascript 中最快的是什么?

$('#myID .myClass')

$('.myClass')

在 CSS 中最好使用什么?

#myID .myClass

.myClass

我现在明白了,我应该解释得更好。对不起!

Ofceauce ID 在 CSS 和 javascript 中都是一个更快的选择器。但有时你需要使用类,因为有多个选择器。

比如说我有一个大的 html 文档。在页面中间我有:

<div id="myID">

<a class="myClass">link1</a>

<a class="myClass">link1</a>

<a class="myClass">link1</a>

</div>

如果我想定位所有“myClass”。那么在定位类之前定位ID会更好吗? (那么我就不必对整个 HTML 文档进行 domtravel)例如:

会这样吗:

$('#myID').find('.myClass')

比:

$('.myClass')

【问题讨论】:

很抱歉,应该只有一个元素具有特定 ID,所以第一个元素可能只是 $('#myID') 还是我误解了你? 不同的浏览器使用不同的DOM选择方法,所以没有一个正确的答案。在旧版浏览器中,$('#myID').find('.myClass') 可能是最快的。在新的浏览器中,我有一种感觉,除非你有一个非常大而复杂的页面,否则你不会看到太大的差异。 感谢您的所有 cmets。实际上我有一个“非常大而复杂的页面”。这就是我提出这个问题的原因,但我只关心现代浏览器。 根据您对“现代”的定义,现代浏览器将使用原生的querySelectorAll 方法,该方法通常非常快。但小心点。 Sizzle(jQuery 的选择器引擎)添加了 querySelectorAll 无法容忍的非标准选择器。因此,如果您使用其中之一,控制权将交给它自己的基于 JavaScript 的引擎,这要慢得多。我认为无论哪种方式,$('#myID').find('.myClass') 都会非常快。 check here 【参考方案1】:

我在 现代 浏览器上的 testing 建议您应该使用其中任何一个,

$('#id').find('.class') // or
$('.class')

不是

$('#id .class')

原因是所有现代浏览器都实现了getElementsByClassName,从而导致按类名进行几乎恒定的时间查找(假设是哈希实现)。哪些浏览器是现代浏览器是另一个主观问题。

【讨论】:

酷测试你到了!也许我应该开始只使用类。 :) 您是否建议在 jQuery 中选择后代元素,我们应该始终使用 .find() 而永远不要使用 CSS3 的空间选择器组合器?【参考方案2】:

它们在大多数现代浏览器中大致相同,因为类名在内部进行了哈希处理。不同之处在于较旧的浏览器没有.getElementsByClassName 或等效方法,因此.myClass 在内部被解析为jQuery,并且dom 中的每个元素都被遍历并检查类名(或者它尽可能使用XPath)。

尽可能尝试使用#myID .myClass,因为它允许jQuery 直接跳转到#myID 并在必要时从那里遍历。

【讨论】:

那么存在于#myID之外的.myClass元素会发生什么? OP 发布了不同的选择器,所以当然有不同的用例,它们都会产生不同的结果。我指出选择.myClass 在现代浏览器中不会比选择#myID .myClass 慢。例如,如果.myClass 的唯一实例在#myID 内部,则在许多浏览器中直接选择.myClass 实际上会更快。不同之处在于,在旧版浏览器中,选择 .myClass 会慢数千倍,因此始终首选 #myID .myClass @BoltClock 你不会用简单的 $('.myClass') 来处理你的案子,如果我误解了你的问题,对不起。或者当您说“那么 .myClass... 会发生什么”时,您的意思是,搜索是如何处理的/性能如何?而且我猜在任何一种情况下(旧浏览器与新浏览器),因为您仅询问.myClass ...它仍然必须从根开始遍历树 -► @zyklus:即使现代浏览器确实有一个.getElementsByClassName() 方法——这个方法是如何以不同的方式实现的,所以@BoltClock 的场景会有所不同? @Flak DiNenno:在我发表评论时,问题中没有上下文,因此比较两个选择器的性能毫无意义,因为它们意味着完全不同的东西——一个匹配每个 .myClass 和另一个仅匹配 ID 中的那些。由于对问题进行了编辑以提供上下文,因此我的评论已过时。 @BoltClock ahhh... 现在有意义了。感谢您花时间解释。【参考方案3】:

让我们从逻辑上思考一下,假设您对浏览器的内部构建方式或浏览器如何访问 DOM 一无所知,但您假设它所做的一切都是合乎逻辑的。

因此,在两个选择器中,最窄的一个会更快地找到您的结果,这难道不是合理的吗?

你有两个选择器,翻译成粗略的英语为

    myClass 的任何元素,它是ID 为myID 的元素的子元素 myClass 类的任何元素

至于“在 CSS 中最好使用什么”,这完全是主观的,因为这取决于您是打算针对 .myClass所有 实例还是仅针对 @987654325 的子实例@。

【讨论】:

它甚至不能是主观的,它只是没有逻辑来决定哪个“更好”,因为两个选择器首先不会选择相同的元素集。哦,是的,请为我投票。 嗯,这就是我所说的“主观”——这取决于个人根据情况做出判断 这实际上不是真的。所有具有内部 .getElementsByClassName 方法的浏览器将具有与基于类名经过哈希处理的事实选择 ID 几乎相同的性能。 @cwolves,我并不是在谈论目前实际的现代浏览器实现,而是更多关于使用逻辑推理来推断哪种方法会更快。即使基于散列的类名方法“几乎相同”,它也不会比查找单个 ID 更快 - 它只能匹配它。 @matt b -- 实际上.myClass 在某些情况下比#myID .myClass 更快,例如当.myClass 的唯一实例在#myID 内部并且您使用的是现代浏览器时.但我明白你的帖子的重点:)【参考方案4】:

其实是个好问题。

假设您已经解析了最大深度为 D 的 N 个元素的 DOM 和 S 条规则的 CSS。然后为所有元素查找样式的任务具有大约O(N*D*S) 的计算复杂度。

显然,并非所有 CSS 选择器都具有相同的计算复杂度。

例如,li.item 选择器和li[class ~= "item"] 需要完全相同的 CPU 资源,因为它们是等效的。 li[class = "item"] 的计算速度更快,因为它不需要扫描空格。

#1 选择器:

#myID .myClass /* #1 */
.myClass /* #2 */

需要更多 CPU 资源,因为您需要完成与案例 #2 完全相同的工作量,另外您需要扫描父/子链(最大 D 个元素)以查找具有“myID”的元素。

这就是纯 CSS 选择器的全部内容。

在 jQuery 和朋友的情况下可能有点不同。理论上,jQuery 引擎可以使用document.getElementById() 来最小化查找集(因此减少 N 数),但这与 CSS 行为不匹配。这是一个示例:http://jsfiddle.net/dnsUF/。这里 jQuery 用#foo 报告了一个元素,但实际上有两个这样的元素。

简历:

在 CSS 案例 #2 中更快 在 jQuery 案例 #1 中可以更快(但在 CSS 意义上技术上可能不正确)。

这是我关于 CSS 选择器复杂性的文章: http://www.terrainformatica.com/2008/07/csss-and-computational-complexity-of-selectors/ 这是如何通过使用样式集来改进它的: http://www.terrainformatica.com/2010/09/style-sets-in-h-smile-core/

【讨论】:

澄清一下:你的意思是#1 在 CSS 中更快,但需要更多的计算机 CPU 资源? +1;很好的答案,但是您的复杂性分析看起来很可疑:您几乎可以肯定地制作一个智能数据结构来比线性扫描更快地查找适当的样式规则;同样,您很可能不需要扫描整个树深度(中间结果可能会被缓存并在节点查找之间共享)。然后当然预期的时间会更短,因为需要完整父扫描的病理选择器可能很少见。同样,我希望类名空格拆分被缓存,并且在选择器评估期间不会发生。 @Eamon Nerbonne:CSS 选择器与 jQuery 选择器在不同的环境中工作。对于 HTML/CSS,您将获得 N DOM 元素和 S 规则。对于任何给定的 DOM 元素,您必须按特定顺序扫描所有 S 选择器,以检查它们是否匹配。如果“是”,则样式将与您目前所拥有的相结合。您可以在此处进行一些优化,但优化不多 - 在任何情况下,初始 DOM 状态都是 O(N*S*D) 我看到你在这里推断的幼稚实现 - if 这就是你实现样式匹配的方式,当然,你需要 O(ND S)。但目前尚不清楚您是否真的需要使用该算法。您可以预处理样式规则以提高匹配效率,例如为类名和元素名等内容创建索引。如果您遇到两个以相同查找键开头的规则...在您的预处理中合并规则并使用类似 TRIE 的结构。在匹配过程中,您at all需要扫描样式规则,这一点都不清楚;您可能可以使用查找树。【参考方案5】:

ID 始终是访问元素的最快方式,因为它们是唯一的。

【讨论】:

我会说相当乐观。如果它们不是唯一的怎么办?所有浏览器都支持具有相同 ID 的多个元素。这是给你的测试:jsfiddle.net/Fu4At @c-smile:你能做到并不意味着你应该这样做。 我已经看到它在行动中发生了 :) 非常棒 @BoltClock:ID 的唯一性是作者的建议。 @c-smile ID 根据定义是唯一的。重用 ID 不仅是不好的做法,而且也不切实际,因为浏览器总是会选择具有该 ID 的第一个元素。【参考方案6】:

是的,id 是访问元素的最快方法之一。看看这个测试http://mootools.net/slickspeed/。

【讨论】:

【参考方案7】:

#myID .myClass 绝对是访问元素的更好方法,假设您有许多应用了.myClass 的元素。

【讨论】:

【参考方案8】:

更新 - 2015 - 在这里检查自己https://jsperf.com/id-vs-class-vs-tag-selectors/2

TL;DR;

在我的 chrome 41 on linux 64bits 上使用 ID $("#foo") 几乎比 CSS $(".bar") 快 4 倍

【讨论】:

以上是关于jquery 和 CSS 中最快的选择器方法 - ID 与否?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery选择器和选取方法

jQuery选择器和选取方法.RP

在我当前的日期选择器代码中禁用特定日期的最快方法?

jQuery选择器和选取方法

jQuery 选择器性能

jQuery选择器和方法