56

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

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

4 回答 4

53

在 jQuery标记信息中会出现此警告:

jQuery 函数 $() 很昂贵。反复调用它效率极低。

嗯......这仅适用于字符串选择器,它会被正则表达式解析以找出它们是什么:

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

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

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

所以是的,它很昂贵,但这仅适用于选择器!

如果我们传递 a 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;
}

用 jsPerf 做了一些测试,我发现缓存 jQuery 对象确实只有一点效果:

条形图,如下所述

在 Chrome 中,它只慢了 7%。(在 IE 中它更重要一点:12%。)

于 2012-05-03T14:02:15.877 回答
14

要回答您的第二个问题,请查看源代码

// Handle $(DOMElement)
if ( selector.nodeType ) {
    this.context = this[0] = selector;
    this.length = 1;
    return this;
}
于 2012-05-03T14:04:54.127 回答
10

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

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

在此处输入图像描述

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

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

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

于 2012-05-03T15:23:31.277 回答
8

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

网络带宽。

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

考虑:

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

闭包编译器的缩小输出是

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)。您可以获得微不足道但可衡量的运行时性能提升。更重要的是,您可以减少通过网络传输的字节数,这直接转化为更多的美元,因为更快的页面加载等于更多的销售额

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

于 2012-05-04T02:26:36.090 回答