我在做this test case查看使用 this
选择器可以加快进程的速度。在这样做的同时,我决定也尝试一下预先保存的元素变量,假设它们会更快。使用测试前保存的元素变量似乎是最慢的,这让我很困惑。我虽然只需要“找到”该元素一次就会极大地加快这个过程。为什么情况并非如此?
以下是我从最快到最慢的测试,以防有人无法加载它:
1
$("#bar").click(function(){
$(this).width($(this).width()+100);
});
$("#bar").trigger( "click" );
<小时/>
2
$("#bar").click(function(){
$("#bar").width($("#bar").width()+100);
});
$("#bar").trigger( "click" );
<小时/>
3
var bar = $("#bar");
bar.click(function(){
bar.width(bar.width()+100);
});
bar.trigger( "click" );
<小时/>
4
par.click(function(){
par.width(par.width()+100);
});
par.trigger( "click" );
我假设顺序是 4, 3, 1, 2,必须使用选择器更频繁地“查找”变量。
更新:我有一个 theory ,但如果可能的话,我希望有人验证这一点。我猜想在单击时,它必须引用变量,而不仅仅是元素,这会减慢速度。
最佳答案
修复测试用例:http://jsperf.com/this-vs-thatjames/10
TL;DR:每个测试中执行的点击处理程序数量都会增加,因为元素在测试之间不会重置。
微优化测试的最大问题是您必须非常非常小心地对待您正在测试的内容。在很多情况下,测试代码会干扰您正在测试的内容。这是一个example来自 Vyacheslav Egorov 的测试“证明”乘法在 JavaScript 中几乎是瞬时的,因为 JavaScript 编译器完全删除了测试循环:
// I am using Benchmark.js API as if I would run it in the d8.
Benchmark.prototype.setup = function() {
function multiply(x,y) {
return x*y;
}
};
var suite = new Benchmark.Suite;
suite.add('multiply', function() {
var a = Math.round(Math.random()*100),
b = Math.round(Math.random()*100);
for(var i = 0; i < 10000; i++) {
multiply(a,b);
}
})
由于您已经意识到存在违反直觉的情况,因此您应该格外小心。
首先,您不是在那里测试选择器。您的测试代码正在执行:零个或多个选择器(具体取决于测试)、函数创建(在某些情况下是闭包,其他情况下不是)、分配为单击处理程序以及触发 jQuery 事件系统。
此外,您正在测试的元素在测试之间会发生变化。很明显,一次测试的宽度比之前测试的宽度要大。但这还不是最大的问题。问题在于一个测试中的元素关联了 X 个单击处理程序。下一个测试中的元素具有 X+1 个点击处理程序。 因此,当您触发最后一个测试的点击处理程序时,您还会触发之前所有测试中关联的点击处理程序,从而使其比之前的测试慢得多。
我修复了 jsPerf,但请记住,它仍然不只测试选择器性能。尽管如此,影响结果的最重要因素还是被消除了。
<小时/>注意:有一些slides和一个video关于使用 jsPerf 进行良好的性能测试,重点关注应避免的常见陷阱。主要思想:
- 不要在测试中定义函数,而是在设置/准备阶段进行
- 使测试代码尽可能简单
- 比较具有相同功能的事物或坦率地说明这一点
- 测试您想要测试的内容,而不是设置代码
- 隔离测试,在每次测试之后/之前重置状态
- 没有随机性。如果需要,请 mock 它
- 注意浏览器优化(死代码删除等)
关于javascript - 为什么 "this"比保存的选择器更有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22596433/