'$(this)'的成本是多少?

时间:2012-05-03 14:01:54

标签: javascript jquery performance

这里的人们经常建议缓存从jQuery元素创建的DOM对象,就像使用以下代码一样:

$('#container input').each(function() {
    $(this).addClass('fooClass');
    $(this).attr('data-bar', "bar");
    $(this).css('background-color', 'red');
});
  • 缓存jQuery对象真的能提高代码的性能吗?
  • 将DOM元素传递给jQuery构造函数时,“幕后”会发生什么?

4 个答案:

答案 0 :(得分:52)

在jQuery tag info中出现此警告:

  

jQuery函数$()很昂贵。反复调用它是非常低效的。

嗯......这对于字符串选择器来说是正确的,它会被正则表达式解析以找出它们是什么:

quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/

然后,如果字符串是一个选择器(id除外),jQuery遍历DOM以找到与其昂贵的find函数的匹配:

} else if ( !context || context.jquery ) {
    return ( context || rootjQuery ).find( selector );
}

所以是的,这是昂贵的,但这只适用于选择者!

如果我们传递DOMElement,jQuery所做的唯一操作就是将DOMElement参数保存为新创建的jQuery对象的上下文,并将上下文的长度设置为1:

// Handle $(DOMElement)
if ( selector.nodeType ) {
    this.context = this[0] = selector; // Selector here is a DOMElement
    this.length = 1;
    return this;
}

我做了some tests with jsPerf,我发现确实缓存jQuery对象只有一点影响:

Bar chart, described below

在Chrome中它的速度只有7%。 (在IE中,它有点重要:12%。)

答案 1 :(得分:14)

要回答第二个问题,请查看source

// Handle $(DOMElement)
if ( selector.nodeType ) {
    this.context = this[0] = selector;
    this.length = 1;
    return this;
}

答案 2 :(得分:10)

关于性能差异,如果您正在寻找两者之间的直接比较,那么删除任何可能会导致结果偏差的额外代码会很有帮助,例如DOM选择和其他不直接相关的方法。< / p>

http://jsperf.com/this-cost/2

enter image description here

在更真实的世界环境中,相对差异很小,因为您的测试显示

要记住的另一件事是每次创建一个jQuery对象时,都需要为它分配内存,这会增加垃圾收集器需要做的工作。

所以我认为人们建议缓存的原因在某种程度上是有原则的。正在进行额外的工作,虽然它通常不会产生明显的影响,但最终还是需要一些可以轻易避免的开销。

答案 3 :(得分:8)

所有运行时性能测试遗漏的一件事是另一个主要考虑因素:

网络带宽。

$(this)缓存到局部变量中通常会减小脚本的大小,特别是在缩小时(因为this不能从四个字符中减少)。

考虑:

function hello(text) {
    $(this).attr();
    $(this).css();
    $(this).data();
    $(this).click();
    $(this).mouseover();
    $(this).mouseleave();
    $(this).html(text);
}
hello('Hello world');

Closure编译器的缩小输出是

function hello(a){$(this).attr();$(this).css();$(this).data();$(this).click();$(this).mouseover();$(this).mouseleave();$(this).html(a)}hello("Hello world");

这节省了39个字节(20%)。现在考虑:

function hello(name) {
    var $this = $(this);
    $this.attr();
    $this.css();
    $this.data();
    $this.click();
    $this.mouseover();
    $this.mouseleave();
    $this.html(name);
}
hello('Hello world');

缩小的输出是

function hello(b){var a=$(this);a.attr();a.css();a.data();a.click();a.mouseover();a.mouseleave();a.html(b)}hello("Hello world");

这节省了74个字节(37%),几乎使我们的字节节省了一倍。显然,在大型脚本中实际节省的成本会更低,但您仍然可以通过缓存来大幅减少脚本的大小。

真的,缓存$(this)只有一个好处。您可以获得微不足道但可测量的运行时性能提升。更重要的是,您可以减少通过网络传输的字节数,并将直接转换为更多美元,因为faster page loads equal more sales

当你以这种方式看待它时,你实际上可以说重复$(this)而不是缓存它是可量化的美元成本