任何人都可以解释这个循环如何设法如此高的基准?

时间:2013-04-07 03:08:08

标签: javascript performance

http://jsperf.com/loops/67

如果你看,下面的循环管理一些疯狂的基准:

var i=0;
var v;
for (i, v; v = arr[i++];) {
   v;
}

在FF中获得约7亿次操作/秒,在Chrome中获得约20万美元,在IE10中获得约50万美元。下一个最快的循环在FF中管理~100k,在IE10中管理约6k,在Chrome中仅管理约2k。

为什么这么快?我可以看到其他循环之间的明显差异,以及一个如何比另一个循环更快,但我无法想出任何可以解释这个循环的绝对令人兴奋的性能差异,7亿到100k是一个疯狂的差距。 / p>


在回答后编辑:

根据@Michael Gary的回答,我回过头来编辑设置以包含一个真实的真实阵列,结果又回归现实:http://jsperf.com/loops/70

2 个答案:

答案 0 :(得分:7)

原因很简单。使用以下代码创建数组arr

var arr = new Array(10000);

所以它的长度为10000,但所有元素都是undefined。这个循环在数组长度上不起作用,但在遇到“假”值时终止 - 假设当v因试图获得undefined值时循环将停止读过数组的末尾。

但是在这个特定的数组中,所有一万个元素的值都为undefined。因此,当测试数组的第一个元素时,循环停止。换句话说,它根本不循环!难怪它很快。

但是更现实世界的情况呢?这种循环如何使用冗长的JSON对象数组:

[
    { "id": 507674, "name": "Kolink" },
    { "id": 997356, "name": "DarkLord7854" },
    { "id": 1202830, "name": "Michael Geary" },
    /* and thousands more */
]

这里你没有立即终止循环的问题,因为数组元素都是“真实的”。

使用现代JavaScript引擎,这是一个写一个循环的相当差的方法,因为我最近发现了我的极度尴尬。

我是jQuery Cookbook的作者之一:我写了第5章的大部分内容,“更快,更简单,更有趣”。嗯,“更快”的部分并没有那么好。我推荐了一个非常类似于你的循环来迭代大量的对象,如上面那样:

for( var item, i = -1;  item = array[++i]; ) {
    // do stuff with item
}

事实证明,在现代浏览器中,这比传统的循环要慢得多:

for( var i = 0, n = array.length;  i < n;  i++ ) {
    var item = array[i];
    // do stuff with item
}

部分原因在于,尝试读取数组末尾的内容会将某些JavaScript引擎重新置于代表数组的去优化方式,正如V8作者之一在Google I / O上向我解释的那样年。部分原因可能是浏览器优化了更常见的循环类型,而不是优化这种不太常见的方法。

无论哪种方式,现代浏览器中传统的循环越快越好:

http://jsperf.com/mikes-loops/2

但这与你的循环不同。在你的情况下,疯狂的性能提升直接归因于它没有在所有上运行循环。 : - )

答案 1 :(得分:3)

arr初始化为包含10000批bugger的数组。 Array(10000)准备数组的长度,但不以任何方式填充它。

因此,arr[0]将为undefined,这是假的,因此for循环会立即终止。

基本上,代码归结为:

var i=0;
var v;
i,v; // doesn't do anything but access the variables
v = undefined;
i++;