7

I setup a simple benchmark for comparing performance of for (const x of arr) and for (let i = 0; i < arr.length; i++) loops. (benchmark link)

Setup code

const arr = [...new Array(10000)].map(() => Math.random()); 

for (let i = 0; i < arr.length; i++)

let sum = 0; for (let i = 0; i < arr.length; i++) { sum += arr[i]; } 

for (const x of arr)

let sum = 0; for (const x of arr) { sum += x; } 

I have re-run the benchmark several times over, and each time, the for-of loop is almost 70% slower than the for-length loop. (~150k ops/sec vs ~43k ops/sec). This is very surprising to me.

What is the reason for this loop being significantly slower?

I have looked at the related thread and the answers there dive into pros/cons of micro-benchmarking, and the conclusion was that switching the test order results in flipping the result. My case is different because I have large arrays (so no micro-bench issues) and I am using a test framework (jsbench.me) to avoid cold start issues.

8
  • 1
    I'm not big on Javascript, but wouldn't that be coming from the fact that the for-of loop uses Iterators (and all the overhead that comes with it) underneath whereas the for-length loop simply iterates over a memory section ? Commented Jul 28, 2022 at 7:16
  • You can optimize for...length loop even further if you save value of arr.length to a variable, because arr.length is an accessor (get/set method) Commented Jul 28, 2022 at 7:33
  • Just have a look at the specification for the "why?" -> for, for...of Commented Jul 28, 2022 at 7:34
  • @AzizHakberdiev That really shouldn't make any difference. Accessors have a time complexity of O(1) and even if it would make a difference, this would likely be optimized by the JIT compiler. Commented Jul 28, 2022 at 8:00
  • 1
    @AzizHakberdiev That's definitely not something I see. All outcomes are very close, twice using array.length in the array condition is slightly faster (1, 2), once using a separate variable is faster (3). Commented Jul 28, 2022 at 9:28

1 Answer 1

4

for...of accesses @iterator method (obj[Symbol.iterator] to access), which is a generator function that contains the for...length loop inside with yield statements

Sign up to request clarification or add additional context in comments.

2 Comments

"which is a generator function that contains the for...length loop inside with yield statements" - Do you have any source for that? I'm pretty confident that the array iterator's code is native and depend on the JS engine that implements it.
@Ivar, chromium.googlesource.com/v8/v8.git/+/3.31.25/src/… even if array iterator is native, it still consumes resources to behave like generators

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.