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

gdo*_*ica 56 javascript performance jquery

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

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

gdo*_*ica 53

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

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

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

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

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

} else if ( !context || context.jquery ) {
    return ( context || rootjQuery ).find( selector );
}
Run Code Online (Sandbox Code Playgroud)

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

如果我们传递一个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;
}
Run Code Online (Sandbox Code Playgroud)

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

条形图,如下所述

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


SLa*_*aks 14

要回答第二个问题,请查看来源:

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

  • 现在字符串选择器显然会有一个非常不同的图形. (3认同)

cli*_*ity 10

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

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

在此输入图像描述

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

另外要记住的是,每次创建jQuery对象时,都需要为其分配内存,这会增加垃圾收集器需要完成的工作.

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


jos*_*736 8

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

网络带宽.

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

考虑:

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

Closure编译器的缩小输出是

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

这节省了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');
Run Code Online (Sandbox Code Playgroud)

缩小的输出是

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

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

真的,缓存只有一个好处$(this).您可以获得微不足道但可测量的运行时性能提升.更重要的是,您可以减少通过线路传输的字节数,并直接转换为更多的美元,因为更快的页面加载等于更多的销售.

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

  • 是的,我只是意味着,如果你是gzipping,那么缓存某些像`this`之类的东西可能会导致一个更大的文件,而不是使用非缓存的`this`来压缩代码的版本.它们肯定都会产生比原始文件更小的文件.保存的百分比并不重要,因为起点不同,而是最终的文件字节大小是需要测量的. (3认同)