【问题标题】:Is jQuery traversal preferred over selectors?jQuery 遍历是否优于选择器?
【发布时间】:2013-02-19 10:38:02
【问题描述】:

使用$("#vacations").find("li").last() 是否比$("#vacations li:last") 更好?

背景和我的想法:

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

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

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

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

【问题讨论】:

  • 这是一个 jspref.com 为您运行的测试jsperf.com/is-jquery-traversal-preferred-over-selectors 您现在可以在不同的浏览器中轻松测试。
  • 不发布新答案,因为它不那么相关,但对开发人员来说,两者都很有用:您可以使用选择器进行初始选择(可能很复杂),将结果保存到 jQuery 对象,然后有条件地运行代码 A 或 B,然后在 A 上运行一种遍历方法,在 B 上运行另一种遍历方法。它比有条件地构建一个字符串来选择正确的元素更容易(并且更不容易出错)。

标签: javascript jquery performance


【解决方案1】:

对此没有直接的答案,但对于您正在使用的:last 选择器,它是对选择器 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,你最好忘记它们。

【讨论】:

    【解决方案2】:

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

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

    选择器字符串可读性较差并且速度较慢,所以真的没有理由使用它。

    通过将选择器字符串分解为 Sizzle 可以快速解析的简单块(#idtagname),您基本上只是将对 getElementByIdgetElementsByTagName 的调用链接在一起,这大约与你可以得到。

    【讨论】:

    • 好一个,所以如果我没有被误解并且我们需要 3 个选择器,那么 $("#my_table").find("tr") 比 $("#my_table tr") 要好得多我们可以像 $().find().find() 一样将它们链接起来,并且仍然可以使当前客户端上的 js 引擎受益。
    • @vtz:计时。我认为在这种特定情况下它不会更快。
    猜你喜欢
    • 2021-11-10
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    相关资源
    最近更新 更多