Jam*_*uld 18 javascript jquery
我正在做这个测试用例,看看使用this选择器加速进程的程度.在这样做时,我决定尝试预先保存的元素变量,假设它们会更快.使用在测试之前保存的元素变量似乎是最慢的,这让我很困惑.我虽然只需要"找到"该元素一次就会极大地加速这个过程.为什么不是这样?
以下是我从最快到最慢的测试,以防任何人无法加载它:
1
$("#bar").click(function(){
$(this).width($(this).width()+100);
});
$("#bar").trigger( "click" );
Run Code Online (Sandbox Code Playgroud)
2
$("#bar").click(function(){
$("#bar").width($("#bar").width()+100);
});
$("#bar").trigger( "click" );
Run Code Online (Sandbox Code Playgroud)
3
var bar = $("#bar");
bar.click(function(){
bar.width(bar.width()+100);
});
bar.trigger( "click" );
Run Code Online (Sandbox Code Playgroud)
4
par.click(function(){
par.width(par.width()+100);
});
par.trigger( "click" );
Run Code Online (Sandbox Code Playgroud)
我假设订单将按顺序进行4,3,1,2,其中必须使用选择器更频繁地"找到"变量.
更新:我有一个理论,但我希望有人在可能的情况下验证这一点.我猜测在点击时,它必须引用变量,而不仅仅是元素,这会减慢它的速度.
修复了测试用例:http://jsperf.com/this-vs-thatjames/10
TL; DR:每个测试中执行的单击处理程序数量增加,因为元素未在测试之间重置.
测试微优化的最大问题是你必须非常小心你正在测试的东西.在许多情况下,测试代码会干扰您正在测试的内容.以下是来自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);
}
})
Run Code Online (Sandbox Code Playgroud)
既然你已经意识到有一些违反直觉的事情,你应该特别小心.
首先,你不是在那里测试选择器.您的测试代码正在执行:零或更多选择器,具体取决于测试,函数创建(在某些情况下是闭包,其他情况不是),作为单击处理程序的赋值和jQuery事件系统的触发.
此外,您正在测试的元素是在测试之间进行更改.很明显,一次测试中的宽度大于之前测试中的宽度.但这不是最大的问题.问题是一个测试中的元素与X点击处理程序相关联.下一个测试中的元素有X + 1个点击处理程序.因此,当您触发上次测试的单击处理程序时,您还会触发之前所有测试中关联的单击处理程序,使其比之前的测试慢得多.
我修复了jsPerf,但请记住它仍然不测试选择器性能.尽管如此,消除了扭曲结果的最重要因素.
注意:有一些幻灯片和一个关于使用jsPerf进行良好性能测试的视频,重点关注您应该避免的常见陷阱.主要观点:
您并没有真正测试不同技术之间的性能.
如果您查看此修改测试的控制台输出:http: //jsperf.com/this-vs-thatjames/8
您将看到有多少事件侦听器附加到该#bar对象.而且你会发现每次测试都没有删除它们.
因此,以下测试将始终变得比以前的测试慢,因为触发器函数必须调用所有先前的回调.