【问题标题】:jQuery selector performance issuesjQuery 选择器性能问题
【发布时间】:2013-06-04 15:51:03
【问题描述】:

我有 3 个关于选择器性能的疑问:

首先,以下语句是否存在性能差异:

$('#content .someclass')$('.someclass', '#content')

我一直使用第一种方式,但最近似乎有更多人转向第二种方式。两者之间有什么好处吗

其次,如果我添加div.someclass,那会比.someclass 更好(如果someclass 的所有元素无论如何都将是div)。我原以为在这种情况下第一个会更慢,因为它必须首先获取所有 div,然后是 .someclass 的那些,但由于我不确定选择器是如何工作的,我只是在猜测

最后,如果我使用$(this),缓存这个对象会更好——var $thisobject = $(this)还是没有区别?我一直认为$(this) 本身就是一个 jQuery 对象,但我现在认为它实际上是将this 转换为一个 jQuery 对象,所以也许将它粘贴到一个变量中会比调用多个 $(this) 更好

【问题讨论】:

  • 第二个是$() 方法的未记录用法。上下文参数必须是元素、jQuery 对象或文档。
  • 您是否尝试过运行自己的任何性能测试,例如在 jsPerf.com 上?
  • 不,我不知道任何性能测试人员。我会去的

标签: jquery performance jquery-selectors


【解决方案1】:

除了您列出的两个之外,还有第三种选择:

1: $('#content .someclass')

2: $('.someclass', '#content')

3: $('#content').find('.someclass')

在不进行任何测试的情况下,我们可以肯定地说 #3 比 #2 快。那是因为#2 在内部变成了#3。这是执行此操作的jQuery source code。它在 init() 函数中,它实际上是 jQuery 构造函数。经过相当长的一系列测试后,它检测到您调用了$(selector,context) 并改为调用$(context).find(selector)

// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
    return this.constructor( context ).find( selector );
}

您可以让$(context).find(selector) 给自己打电话,避免额外的检查。

所以#2 永远不是最快的代码; #3 总会打败它。

也正如@KevinB 指出的那样,#2 是not a documented use$/jQuery 函数。这可能只是文档中的一个疏忽,因为它是对 #3 的直接转换,这是该函数的记录使用,并且代码多年来一直以这种方式工作。

在任何情况下,几乎没有任何理由使用 #2,即使在其记录的案例中,因为 #3 更快且更易于理解。

#3 与 #1 相比如何?在大多数情况下可能更快,但它可能因浏览器以及特定选择器和页面复杂性而异。 jsPerf 是你的朋友,但一定要给它一个与重要页面相似的页面,而不仅仅是一个人为的测试。

div.someclass.someclass 相同。测试一下看看。

关于$(this),当$ 函数名称只是普通的JavaScript 函数调用时,它们有时会让事情看起来很神奇。为便于理解,请尝试改用 jQuery 函数名:

jQuery(this)

现在应该更清楚了,这确实是一个函数调用,而不是某种神奇的语法。当您使用$(this)$(anything) 时也是如此:它始终 是一个函数调用。所以是的,如果您重复使用它,最好将结果保存在变量中:

var $this = $(this);

我唯一的建议是不要将变量命名为 $thisobject。额外的object 措辞并没有真正使名称更加清晰;一个简单的$this 会让其他开发者更加熟悉。或者使用更具描述性的名称可能更好,例如

var $element = $(this);

一般来说,this$this 在 jQuery 代码中被严重过度使用,最好尽可能使用具有简短但描述性名称的普通变量。

考虑一下这个人为的 jQuery 插件:

jQuery.fn.log = function() {
    this.each( function() {
        console.log( this );
    });
    return this;
};

在这个简短的函数中,this 改变了两次含义:首先是 jQuery 对象,然后是来自该对象的单个元素,然后又是 jQuery 对象。难怪人们对this 有麻烦!

相反,您可以使用.each() 的命名参数:

$.fn.log = function() {
    this.each( function( i, element ) {
        console.log( element );
    });
    return this;
};

这不那么令人困惑了,如果您在内部函数中需要一个用于 element 的 jQuery 对象,您可以使用与 this 相同的方式进行操作:

var $element = $(element);

【讨论】:

  • 我很高兴,很高兴它有帮助。
【解决方案2】:

这取决于选择器的确切性质。

一般最好让浏览器完成所有繁重的工作,因为它可以直接访问 DOM,因此您可能期望前者更快。

AIUI,浏览器通常在选择器中从“右到左”工作,因此它会找到所有具有类 .someclass 的元素,然后 然后 将结果过滤为 #content 的后代.

但在这种特定情况下,“父级”由 ID 标识,因此告诉浏览器从该特定元素开始并仅考虑其后代可能会更快。

换句话说,“视情况而定”。在真实页面或 jsperf.com 上尝试一下,看看会发生什么。

【讨论】:

    【解决方案3】:

    尚未提及的是浏览器之间会有所不同。在不支持querySelectorAll 的浏览器中,策略会发生变化。例如,如果浏览器确实支持该方法,那么 $('#id').find(' > li > a') 之类的东西可能会非常快...... @。

    【讨论】:

    • 我认为它只是IE 6,我相信7支持querySeletorAll。我知道有 8 个。
    猜你喜欢
    • 1970-01-01
    • 2010-11-27
    • 2011-06-23
    • 1970-01-01
    • 2011-04-04
    • 2011-10-31
    相关资源
    最近更新 更多