什么是在JavaScript中循环访问数组的最快方法?
我从书本上了解到,你应该这样写:
for(var i=0, len=arr.length; i < len; i++){ // blah blah }
所以arr.length
不会每次计算。
其他人则说编译器会对此做一些优化,所以你可以写:
for(var i=0; i < arr.length; i++){ // blah blah }
我只想知道在实践中哪个是最好的方法?
用最现代的浏览器进行这个testing之后…
目前 ,最快的循环forms(在我看来,语法最明显)。
具有长度caching的循环标准
for (var i = 0, len = myArray.length; i < len; i++) { }
我会说这绝对是一个我赞扬JavaScript引擎开发人员的情况。 运行时间应该为了清晰 而不是巧妙而优化。
通过JavaScript数组循环的绝对最快的方法是:
var len = arr.length; while (len--) { // blah blah }
请参阅http://blogs.oracle.com/greimer/entry/best_way_to_code_a进行全面比较;
如果顺序不重要,我更喜欢这种风格:
for(var i = array.length; i--; )
它caching的长度,写得更短。 但它会以相反的顺序遍历数组。
2014 While
回来了
只是想逻辑。
看这个
for( var index = 0 , length = array.length ; index < length ; index++ ) { //do stuff }
- 需要创build至less2个variables(索引,长度)
- 需要检查索引是否小于长度
- 需要增加索引
-
for
循环有3个参数
现在告诉我为什么这应该比以下更快:
var length = array.length; while( --length ) { //or length-- //do stuff }
- 一个variables
- 没有检查
- 指数下降(机器更喜欢)
-
while
只有一个参数
当Chrome 28显示for循环比while循环更快时,我完全感到困惑。 这肯定有某种好处
“呃,每个人都在使用for循环,让我们专注于为Chrome开发。”
但是现在,在2014年,while循环又回来了。 它快了2倍,在其他/旧版浏览器上它总是更快。
最近我做了一些新的testing。 现在在现实世界中,这些短代码是没有价值的,jsperf实际上不能正确执行while循环,因为它需要重新创buildarray.length,这也需要时间。
你不能得到jsperf的while循环的实际速度。
你需要创build你自己的自定义函数,并用window.performance.now()
是的,没有办法,while循环只是更快。
真正的问题实际上是dom操作/渲染时间/绘制时间,或者你想调用它。
例如,我有一个canvas场景,我需要计算坐标和碰撞…这是在10-200微秒(而不是毫秒)之间完成的。 它实际上需要不同的毫秒来渲染一切。
但
在某些情况下,使用for loop
还有另一种超级执行方式…例如复制/克隆数组
for( var i = array.length ; i > 0 ; arrayCopy[ --i ] = array[ i ] // doing stuff );
注意参数的设置:
- 和while循环一样,我只使用一个variables
- 需要检查索引是否大于0;
- 正如你可以看到这个方法是不同的,每个人都使用正常的循环,因为我做的东西里面的第三个参数,我也直接减less数组内。
说,这证实了机器喜欢 –
写我正在考虑使它变短一点,删除一些无用的东西,并使用相同的风格写这个:
for( var i = array.length ; i-- ; arrayCopy[ i ] = array[ i ] // doing stuff );
即使它更短,它看起来像使用i
再一次减慢了一切。 它比前一个循环和一个循环慢1/5。
注意: 之后是非常重要的for looo without {}
即使我只是告诉你,jsperf不是testing脚本的最佳方法..我在这里添加了2个循环
http://jsperf.com/caching-array-length/40
这里是另一个关于JavaScript性能的答案
https://stackoverflow.com/a/21353032/2450730
这个答案是显示高效的写作方式的JavaScript。 所以,如果你不能阅读,问,你会得到一个答案或阅读关于JavaScript的书http://www.ecma-international.org/ecma-262/5.1/
截至2016年6月 ,在最新的Chrome浏览器(2016年5月浏览器市场的71%,并增加)进行一些testing:
- 最快的循环是一个循环 ,无论是否有caching长度提供真正相似的性能。 (具有caching长度的for循环有时会比没有caching的情况提供更好的结果,但差别几乎可以忽略不计,这意味着引擎可能已经被优化以支持标准,而且可能最直接的用于没有caching的循环。
- 递减的while循环大约比for循环慢1.5倍。
- 使用callback函数的循环(比如forEach的标准)比for循环慢大约10倍。
我认为这个线程太旧了,错误的程序员认为他们需要caching长度,或者使用递减遍历来实现更好的性能,编写比简单直接的循环更不易读,更容易出错的代码。 所以我build议:
-
如果您的应用程序遍历了很多项目,或者您的循环代码位于经常使用的函数中,那么直接循环就是答案:
for (var i = 0; i < arr.length; i++) { // Do stuff with arr[i] or i }
-
如果你的应用程序没有真正地迭代大量的项目,或者你只需要在这里和那里做小的迭代,使用标准的forEachcallback或从你select的JS库中的任何类似的函数可能会更容易理解,索引variables作用域被closures,你不需要使用括号,直接访问数组值:
arr.forEach(function(value, index) { // Do stuff with value or index });
-
如果您真的需要在几十毫秒的时间内重复几十毫秒,并且数组的长度在整个过程中不变,那么可以考虑在for循环中caching长度。 虽然我觉得现在真的没这个必要了:
for (var i = 0, len = arr.length; i < len; i++) { // Do stuff with arr[i] }
http://jsperf.com/caching-array-length/60
我准备的(通过重复使用较旧的)最新的testing版本显示了一件事。
caching的长度并不是那么重要,但是并没有什么坏处。
在我的Debian Squeeze 64位( 我的桌面硬件 )中,每一次上面链接的testing(在新近打开的标签上)都能为Chrome,Opera和Firefox中的最后4个片段(图表中的第3,第5,第7和第10) )。 后续运行给出了完全不同的结果。
性能明智的结论很简单:
- 去循环(向前)和testing使用
!==
而不是<
。 - 如果以后不需要重用数组,那么循环减less的长度和破坏性的
shift()
数组也是有效的。
TL;博士
如今(2011.10)以下模式看起来是最快的。
for (var i = 0, len = arr.length; i !== len; i++) { ... }
注意cachingarr.length
在这里并不重要,所以你可以testingi !== arr.length
并且性能不会下降,但是你会得到更短的代码。
PS:我知道在使用shift()
代码片段中,可以使用它的结果而不是访问第0个元素,但是我忽略了在重新使用之前的修订版本(while循环有错误)之后,后来我不想失去已经获得的结果。
纯粹performance中的“最佳”? 或性能和可读性?
纯性能“最好”是这样的,它使用caching和++前缀操作符(我的数据: http : //jsperf.com/caching-array-length/189 )
for (var i = 0, len = myArray.length; i < len; ++i) { // blah blah }
我认为无caching的for循环是执行时间和程序员读取时间的最佳平衡。 每一个以C / C ++ / Java开始的程序员都不会浪费一个不得不阅读这个的程序员
for(var i=0; i < arr.length; i++){ // blah blah }
**caching循环内的数组长度,几秒钟的时间将被避免。 如果数组中有更多项目,则取决于数组中的项目,这与时间Ms有很大的区别*
**
sArr; //Array[158]; for(var i = 0 ; i <sArr.length ; i++) { callArray(sArr[i]); //function call } ***end: 6.875ms***
**
**
sArr; //Array[158]; for(var i = 0,len = sArr.length ; i < len ; i++) { callArray(sArr[i]); //function call } ***end: 1.354ms***
**
这看起来是迄今为止最快的方式 …
var el; while (el = arr.shift()) { el *= 2; }
考虑到这将消耗arrays,吃它,并留下一切…
我总是写在第一种风格。
即使编译器足够聪明,可以对数组进行优化,但是如果我们在这里使用DOMNodeList还是一些计算长度的复杂对象,它仍然很聪明?
我知道数组的问题是什么,但是我认为将所有的循环写入一种风格是一个好习惯。
这是2017年 。
我做了一些testing。
https://jsperf.com/fastest-way-to-iterate-through-an-array/
看起来像方法是在Chrome上最快的。
看起来左边的递减( --i
)比Firefox上的其他( ++i
, i++
, i++
)要快得多。
这种方法是平均禁食。 但它以相反的顺序迭代数组。
let i = array.length; while (--i >= 0) { doSomething(array[i]); }
如果转发订单很重要,请使用此方法。
let ii = array.length; let i = 0; while (i < ii) { doSomething(array[i]); ++i; }
var arr = []; // The array var i = 0; while (i < arr.length) { // Do something with arr[i] i++; }
我++比++更快,–i和i–
此外,你可以保存最后一行,你需要访问我最后一次做arr [i ++](但这很难debugging)。
你可以在这里testing它(与其他循环testing): http : //jsperf.com/for-vs-whilepop/5
我知道的最优雅的解决scheme是使用地图。
var arr = [1,2,3]; arr.map(function(input){console.log(input);});
我已经尝试了一些其他方法来迭代一个巨大的数组,发现将数组长度减半,然后在一个循环中迭代两个半部分的速度会更快。 处理巨大的数组时可以看到这种性能差异。
var firstHalfLen =0; var secondHalfLen = 0; var count2=0; var searchterm = "face"; var halfLen = arrayLength/2; if(arrayLength%2==halfLen) { firstHalfLen = Math.ceil(halfLen); secondHalfLen=Math.floor(halfLen); } else { firstHalfLen=halfLen; secondHalfLen=halfLen; } for(var firstHalfCOunter=0,secondHalfCounter = arrayLength-secondHalfLen; firstHalfCOunter < firstHalfLen; firstHalfCOunter++) { if(mainArray[firstHalfCOunter].search(new RegExp(searchterm, "i"))> -1) { count2+=1; } if(secondHalfCounter < arrayLength) { if(mainArray[secondHalfCounter].search(new RegExp(searchterm, "i"))> -1) { count2+=1; } secondHalfCounter++; } }
一些性能比较(使用timer.js)之间的caching长度for循环VS上述方法。
另一个jsperf.comtesting: http ://jsperf.com/while-reverse-vs-for-cached-length
while while循环似乎是最快的。 唯一的问题是,而( – i)将停在0。我怎样才能访问我的循环中的数组[0]呢?
截至2017年9月, 这些jsperftesting显示以下模式在Chrome 60上performance最佳:
function foo(x) { x; }; arr.forEach(foo);
有人能够重现吗?
一个基本的while循环往往是最快的。 jsperf.com是一个伟大的沙箱来testing这些types的概念。