I learned from books that you should write for loop like this:
for(var i=0, len=arr.length; i < len; i++){
// blah blah
}
so the arr.length will not be calculated each time.
Others say that the compiler will do some optimization to this, so you can just write:
for(var i=0; i < arr.length; i++){
// blah blah
}
I just want to know which is the best way in practice?
-
2also worth a look when dealing with array looping: jsperf.com/array-loop-var-cachingcloakedninjas– cloakedninjas2012年06月29日 09:12:52 +00:00Commented Jun 29, 2012 at 9:12
-
@wong2 Tthis benchmark from Browserdiet has a more complete collection of alternatives.Domi– Domi2014年01月09日 12:26:08 +00:00Commented Jan 9, 2014 at 12:26
-
1jsben.ch/#/y3SpCEscapeNetscape– EscapeNetscape2016年10月21日 08:47:10 +00:00Commented Oct 21, 2016 at 8:47
-
Improved on the previous jsben: jsben.ch/#/R6LbSCorbfon– Corbfon2017年05月20日 20:32:05 +00:00Commented May 20, 2017 at 20:32
-
1It looks like the answer is constantly changing and dependent on the engine. If you need speed, just go with a standard for loop and leave out all of the extra tricks. While these special tricks let you trade readability for slightly faster code today, the engines will continue to evolve, and the special tricks may become less effective, potentially even making your code slightly slower.Scotty Jamison– Scotty Jamison2021年02月04日 20:09:47 +00:00Commented Feb 4, 2021 at 20:09
25 Answers 25
After performing this test with most modern browsers: https://jsben.ch/wY5fo
Currently, the fastest form of loop (and in my opinion the most syntactically obvious).
A standard for-loop with length caching
var i = 0, len = myArray.length;
while (i < len) {
// your code
i++
}
I would say, this is definitely a case where I applaud JavaScript engine developers. A runtime should be optimized for clarity, not cleverness.
26 Comments
++i.for(var i=0, len=myArray.length; i<len; ++i) Check jsperf.com/caching-array-length/84 var statement. How it is written, len is actually scoped as you suggest.The absolute fastest way to loop through a javascript array is:
var len = arr.length;
while (len--) {
// blah blah
}
See this post for a full comparison
9 Comments
var (else len becomes a global variable). Also, see jsperf.com/loops for more loop benchmarks.As of June 2016, doing some tests in latest Chrome (71% of the browser market in May 2016, and increasing):
- The fastest loop is a for loop, both with and without caching length delivering really similar performance. (The for loop with cached length sometimes delivered better results than the one without caching, but the difference is almost negligible, which means the engine might be already optimized to favor the standard and probably most straightforward for loop without caching).
- The while loop with decrements was approximately 1.5 times slower than the for loop.
- A loop using a callback function (like the standard forEach), was approximately 10 times slower than the for loop.
I believe this thread is too old and it is misleading programmers to think they need to cache length, or use reverse traversing whiles with decrements to achieve better performance, writing code that is less legible and more prone to errors than a simple straightforward for loop. Therefore, I recommend:
If your app iterates over a lot of items or your loop code is inside a function that is used often, a straightforward for loop is the answer:
for (var i = 0; i < arr.length; i++) { // Do stuff with arr[i] or i }If your app doesn't really iterate through lots of items or you just need to do small iterations here and there, using the standard forEach callback or any similar function from your JS library of choice might be more understandable and less prone to errors, since index variable scope is closed and you don't need to use brackets, accessing the array value directly:
arr.forEach(function(value, index) { // Do stuff with value or index });If you really need to scratch a few milliseconds while iterating over billions of rows and the length of your array doesn't change through the process, you might consider caching the length in your for loop. Although I think this is really not necessary nowadays:
for (var i = 0, len = arr.length; i < len; i++) { // Do stuff with arr[i] }
9 Comments
for(let i=0, j=array.length; i < j; i++), the forward for loops speed up considerably. On a few tests I ran it won, on most it was within the margin of error or the reverse loop.It's just 2018 so an update could be nice...
And I really have to disagree with the accepted answer.
It differs on different browsers. Some do forEach faster, some for-loop, and some while
here is a benchmark on all methods https://jsben.ch/mW36e
arr.forEach( a => {
// ...
}
and since you can see a lot of for-loops like for(a = 0; ... ) then it's worth to mention that without 'var', variables will be defined globally and this can dramatically affect speed so it'll get slow.
Duff's device run faster on opera but not in firefox
var arr = arr = new Array(11111111).fill(255);
var benches =
[ [ "empty", () => {
for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
for(var a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
}]
, ["for-loop++", () => {
for(var a = 0, l = arr.length; a < l; a++)
var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
for(var a = 0; a < arr.length; ++a )
var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
for(var a = arr.length - 1; a >= 0; --a )
var b = arr[a] + 1;
}]
,["while-loop", () => {
var a = 0, l = arr.length;
while( a < l ) {
var b = arr[a] + 1;
++a;
}
}]
, ["reverse-do-while-loop", () => {
var a = arr.length - 1; // CAREFUL
do {
var b = arr[a] + 1;
} while(a--);
}]
, ["forEach", () => {
arr.forEach( a => {
var b = a + 1;
});
}]
, ["for const..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( const a in ar ) {
var b = a + 1;
}
}]
, ["for let..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( let a in ar ) {
var b = a + 1;
}
}]
, ["for var..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( var a in ar ) {
var b = a + 1;
}
}]
, ["Duff's device", () => {
var len = arr.length;
var i, n = len % 8 - 1;
if (n > 0) {
do {
var b = arr[len-n] + 1;
} while (--n); // n must be greater than 0 here
}
n = (len * 0.125) ^ 0;
if (n > 0) {
do {
i = --n <<3;
var b = arr[i] + 1;
var c = arr[i+1] + 1;
var d = arr[i+2] + 1;
var e = arr[i+3] + 1;
var f = arr[i+4] + 1;
var g = arr[i+5] + 1;
var h = arr[i+6] + 1;
var k = arr[i+7] + 1;
}
while (n); // n must be greater than 0 here also
}
}]];
function bench(title, f) {
var t0 = performance.now();
var res = f();
return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
// Here if you forget to put 'var' so variables'll be global
for(a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
});
var times = benches.map( function(a) {
arr = new Array(11111111).fill(255);
return [a[0], bench(...a)]
}).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
`<div>` +
`<span>${title} </span>` +
`<span style="width:${3+n/2}%"> ${Number(time.toFixed(3))}msec</span>` +
`</div>`;
var strRes = times.map( t => template(...t) ).join("\n") +
`<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div { clear:both }
body > div > div > span {
float:left;
width:43%;
margin:3px 0;
text-align:right;
}
body > div > div > span:nth-child(2) {
text-align:left;
background:darkorange;
animation:showup .37s .111s;
-webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>
8 Comments
If the order is not important, I prefer this style:
for(var i = array.length; i--; )
It caches the length and is much shorter to write. But it will iterate over the array in reverse order.
3 Comments
i-- returns a number and once the number is 0 the condition is false because Boolean(0) === false.2014 While is back
Just think logical.
Look at this
for( var index = 0 , length = array.length ; index < length ; index++ ) {
//do stuff
}
- Need to create at least 2 variables (index,length)
- Need to check if the index is smaller than the length
- Need to increase the index
- the
forloop has 3 parameters
Now tell me why this should be faster than:
var length = array.length;
while( --length ) { //or length--
//do stuff
}
- One variable
- No checks
- the index is decreased (Machines prefer that)
whilehas only one parameter
I was totally confused when Chrome 28 showed that the for loop is faster than the while. This must have ben some sort of
"Uh, everyone is using the for loop, let's focus on that when developing for chrome."
But now, in 2014 the while loop is back on chrome. it's 2 times faster , on other/older browsers it was always faster.
Lately i made some new tests. Now in real world envoirement those short codes are worth nothing and jsperf can't actually execute properly the while loop, because it needs to recreate the array.length which also takes time.
you CAN'T get the actual speed of a while loop on jsperf.
you need to create your own custom function and check that with window.performance.now()
And yeah... there is no way the while loop is simply faster.
The real problem is actually the dom manipulation / rendering time / drawing time or however you wanna call it.
For example i have a canvas scene where i need to calculate the coordinates and collisions... this is done between 10-200 MicroSeconds (not milliseconds). it actually takes various milliseconds to render everything.Same as in DOM.
BUT
There is another super performant way using the for loop in some cases... for example to copy/clone an array
for(
var i = array.length ;
i > 0 ;
arrayCopy[ --i ] = array[ i ] // doing stuff
);
Notice the setup of the parameters:
- Same as in the while loop i'm using only one variable
- Need to check if the index is bigger than 0;
- As you can see this approach is different vs the normal for loop everyone uses, as i do stuff inside the 3th parameter and i also decrease directly inside the array.
Said that, this confirms that machines like the --
writing that i was thinking to make it a little shorter and remove some useless stuff and wrote this one using the same style:
for(
var i = array.length ;
i-- ;
arrayCopy[ i ] = array[ i ] // doing stuff
);
Even if it's shorter it looks like using i one more time slows down everything.
It's 1/5 slower than the previous for loop and the while one.
Note: the ; is very important after the for looo without {}
Even if i just told you that jsperf is not the best way to test scripts .. i added this 2 loops here
http://jsperf.com/caching-array-length/40
And here is another answer about performance in javascript
https://stackoverflow.com/a/21353032/2450730
This answer is to show performant ways of writing javascript. So if you can't read that, ask and you will get an answer or read a book about javascript http://www.ecma-international.org/ecma-262/5.1/
5 Comments
for was faster then the while, and I once read on crome-dev it was exactly because of the reason you mention. It would be just a matter of time before while would catch up again. From that point on, the logic in the first part of your answer will hold (once again, yay)! However Modern implementations no longer rigidly follow every ecma-specified step (they optimize). Since now your engine is no longer the most noticeable bottle-neck, one can now actually notice the CPU cache-misses in reverse loops!index-- will evaluate to false when index is 0, which you don't want if you're iterating over everything in an arrayhttp://jsperf.com/caching-array-length/60
The latest revision of test, which I prepared (by reusing older one), shows one thing.
Caching length is not that much important, but it does not harm.
Every first run of the test linked above (on freshly opened tab) gives best results for the last 4 snippets (3rd, 5th, 7th and 10th in charts) in Chrome, Opera and Firefox in my Debian Squeeze 64-bit (my desktop hardware). Subsequent runs give quite different result.
Performance-wise conclusions are simple:
- Go with for loop (forward) and test using
!==instead of<. - If you don't have to reuse the array later, then while loop on decremented length and destructive
shift()-ing array is also efficient.
tl;dr
Nowadays (2011.10) below pattern looks to be the fastest one.
for (var i = 0, len = arr.length; i !== len; i++) {
...
}
Mind that caching arr.length is not crucial here, so you can just test for i !== arr.length and performance won't drop, but you'll get shorter code.
PS: I know that in snippet with shift() its result could be used instead of accessing 0th element, but I somehow overlooked that after reusing previous revision (which had wrong while loops), and later I didn't want to lose already obtained results.
2 Comments
"Best" as in pure performance? or performance AND readability?
Pure performance "best" is this, which uses a cache and the ++prefix operator (my data: http://jsperf.com/caching-array-length/189)
for (var i = 0, len = myArray.length; i < len; ++i) {
// blah blah
}
I would argue that the cache-less for-loop is the best balance in execution time and programmer reading time. Every programmer that started with C/C++/Java won't waste a ms having to read through this one
for(var i=0; i < arr.length; i++){
// blah blah
}
1 Comment
len is named, one would always have to do a double take on that first loop. The second loop's intention is obvious.**cache the array length inside the loop ,some seconds of time will be eluded . Depends on the items in the array if there are more items in array there is major difference with respect to Ms of time*
**
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***
**
Comments
This looks to be the fastest way by far...
var el;
while (el = arr.shift()) {
el *= 2;
}
Take into account that this will consume the array, eating it, and leaving nothing left...
5 Comments
arr.shift(); instead of arr.pop() so that array reverse can be avoided.Benchmarking [10000000] element array...
The fastest [for ++] took [76762166ns]
┌─────────┬───────────────────────┬────────────┬──────────┐
│ (index) │ type │ time[ns] │ baseline │
├─────────┼───────────────────────┼────────────┼──────────┤
│ 0 │ 'for ++' │ 76762166 │ 1 │
│ 1 │ 'for of' │ 82407583 │ 1.07 │
│ 2 │ '--while forward' │ 83723083 │ 1.09 │
│ 3 │ 'do while forward --' │ 83942958 │ 1.09 │
│ 4 │ '--do while forward' │ 84225584 │ 1.1 │
│ 5 │ 'while forward --' │ 85156957 │ 1.11 │
│ 6 │ '--while >= 0' │ 89745916 │ 1.17 │
│ 7 │ '++ do while' │ 90306542 │ 1.18 │
│ 8 │ 'for !== ++' │ 90319083 │ 1.18 │
│ 9 │ '-- for' │ 90360167 │ 1.18 │
│ 10 │ 'for i length --' │ 90558833 │ 1.18 │
│ 11 │ '++ for' │ 90616125 │ 1.18 │
│ 12 │ 'do while ++' │ 90657541 │ 1.18 │
│ 13 │ '--for i length' │ 90757708 │ 1.18 │
│ 14 │ 'for --' │ 90799875 │ 1.18 │
│ 15 │ '++ while' │ 92697417 │ 1.21 │
│ 16 │ '++ for !==' │ 94488209 │ 1.23 │
│ 17 │ 'pop' │ 108399917 │ 1.41 │
│ 18 │ 'while ++' │ 109276500 │ 1.42 │
│ 19 │ 'forEach call' │ 147140124 │ 1.92 │
│ 20 │ 'forEach' │ 148886207 │ 1.94 │
│ 21 │ 'map' │ 207100583 │ 2.7 │
│ 22 │ 'Array from' │ 353166207 │ 4.6 │
│ 23 │ 'flatMap' │ 1213152082 │ 15.8 │
│ 24 │ 'Object.keys map' │ 1294475333 │ 16.86 │
│ 25 │ 'for in' │ 1338988749 │ 17.44 │
└─────────┴───────────────────────┴────────────┴──────────┘
Tested on Macbook Air M1 2020. NodeJS 18.
For arrays with 10_000_000 elements, the standard for loop wins. For other cases see my gist: https://gist.github.com/episage/076ded007d0583f6a275f93a8c9c8047#file-result-txt
Shoutout to @DungGramer. I fixed bugs and enhanced his benchmark.
3 Comments
for(x of array), array.foreach() and the 60 years old classic for loop with index access and index increment where I couldn't believe the classic loops was faster than the other two. Attempt to guess a reason: foreach has a function call for each loop and for-of has the iterator for which I don't get why it should be slower than the classic loop.It's the year 2017.
I made some tests.
https://jsperf.com/fastest-way-to-iterate-through-an-array/
Looks like the while method is the fastest on Chrome.
Looks like the left decrement (--i) is much faster than the others (++i, i--, i++) on Firefox.
This approach is the fasted on average. But it iterates the array in reversed order.
let i = array.length;
while (--i >= 0) {
doSomething(array[i]);
}
If the forward order is important, use this approach.
let ii = array.length;
let i = 0;
while (i < ii) {
doSomething(array[i]);
++i;
}
4 Comments
let you are actually comparing scope creation performance instead of loop performance. Using let i = 0, ii = array.length in your for loops will create a new scope for those variables inside the for block. Your while examples do not create a new scope for the variables inside the while block and that's why they are faster. If you use var instead of let in your for loops, you'll see how for loops are still as fast as whiles in 2017, but more readable.var and let have the same performance - stackoverflow.com/a/32345435/1785975 while being faster in Chrome" accurate. It's only if using let due to performance issues of that keyword in Chrome. If using var or with other browsers, for and while are pretty much the same, sometimes for is even faster depending of the benchmark, and it is more compact and readable imho.I have a test all way in here. Check this! https://gist.github.com/DungGramer/7efdfefecaa1b8f5d6510202524dc751
My result:
popis fastest,forEachis goodest for readable and fastdo..whilefaster thanfor- loop faster if no have condition (like
if) --iis fastest
2 Comments
pop. arrClone is empty when you try to iterate itfor ++ wins for large arrays.I'm always write in the first style.
Even if a compiler is smart enough to optimize it for arrays, but still it smart if we are using DOMNodeList here or some complicated object with calculated length?
I know what the question is about arrays, but i think it is a good practice to write all your loops in one style.
Comments
var arr = []; // The array
var i = 0;
while (i < arr.length) {
// Do something with arr[i]
i++;
}
i++ is faster than ++i, --i and i--
Also, you can save the last line doing arr[i++] the last time you need to access i (but this can be hard to debug).
You can test it here (with other loop tests): http://jsperf.com/for-vs-whilepop/5
2 Comments
++i is faster...As of September 2017 these jsperf tests are showing the following pattern to be most performant on Chrome 60:
function foo(x) {
x;
};
arr.forEach(foo);
Is anyone able to reproduce?
1 Comment
Fastest approach is the traditional for loop. Here is a more comprehensive performance comparison.
https://gists.cwidanage.com/2019/11/how-to-iterate-over-javascript-arrays.html
Comments
If you want a faster for loop, define your variables outside the loop and use below syntax
const iMax = lengthOftheLoop;
var i = 0;
for (; i < iMax; i++) {
console.log("loop"+i);
}
reference: https://medium.com/kbdev/voyage-to-the-most-efficient-loop-in-nodejs-and-a-bit-js-5961d4524c2e
Comments
although it is a very old question, it is a very interesting one,
pardon me for tweaking the question a little bit but I am going to answer it at the end.
the question made me ask myself if there are any better methods for looping in js:
so I have made some tests and here is what I found out: enter image description here
for 1000_000 record: the best is forEach.
for 100 records: it simply doesn't matter.
to go back to your question:
the example i created is not exactly like the question .. but i found out some interesting things:
firstly : like what you said , the arr.length will evaluate every time if it is within the comparison statement i < arr.length ...
note : the variable of arrLength below is not more than the a number of 1000_000 records..
for instance : this wont work enter image description here
but this will
and it will take .036 seconds .. which is very large compared to what it takes if the number was constant...
to sum up,
it is better to use FOREACH
in your case: the i<arr.length should take more time ( around 1.3 the usual)
see the tests : see the tests
Comments
I have tried some other ways to iterate a huge array and found out that halving the array length and then iterating both halves in a single loop is faster. This performance difference can be seen while processing huge arrays.
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++;
}
}
Some performance comparison (using timer.js) between the cached length for-loop VS the above method.
Comments
Another jsperf.com test: http://jsperf.com/while-reverse-vs-for-cached-length
The reverse while loop seems to be the fastest. Only problem is that while (--i) will stop at 0. How can I access array[0] in my loop then?
1 Comment
while (i--) then the truthfulness of i will be tested before decrementing rather than decrementing and then testing truthfulness.A basic while loop is often the fastest. jsperf.com is a great sandbox to test these types of concepts.
Comments
The most elegant solution I know of is using map.
var arr = [1,2,3];
arr.map(function(input){console.log(input);});
2 Comments
[1,2,3].map(console.log)Try this:
var myarray =[],
i = myarray.lenght;
while(i--){
// do somthing
}
Comments
It is late 2022
Sometimes is ineffective calculate with array length at all:
If you have an array with indexes var myArray = [1,2,3,4,25,999999999999] it is very slow to use any solution which is going trough array with increasing index by one (including forEach).
Best solution for me, and it is not mentioned in any top-voted answer is:
for(let _i in myArray ) {
if(myArray[_i]) {
(function(s) {
///
})(myArray[_i])
}
}
7 Comments
for...in construct loops over the enumerable properties of an object. This is very different from iterating the elements of an array, has no guaranteed order, will include the length property, and will likely lead to worse performance. It's simply not meant to be used for array iteration. Furthermore, the code you wrote will only run the inner function for the enumerable properties whose values are truthy.