jQuery选择器性能问题

时间:2013-06-04 15:51:03

标签: jquery performance jquery-selectors

我有3个关于选择器性能的查询:

首先,以下陈述中是否存在任何性能差异:

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

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

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

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

3 个答案:

答案 0 :(得分:1)

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

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

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

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

换句话说,“它取决于”。尝试在真实页面上,或在jsperf.com上,看看会发生什么。

答案 1 :(得分: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是$ / jQuery函数的not a documented use。这可能只是对文档的疏忽,因为它是对#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 :(得分:1)

未提及的是浏览器之间存在差异。在不支持querySelectorAll的浏览器中,策略会发生变化。例如,如果浏览器确实支持该方法,那么类似$('#id').find(' > li > a')的东西可能会非常快......在没有的浏览器上(遗留的IE,最值得注意的是),你可能会更喜欢类似的东西$('#id').children('li').children('a')