loading...

Array.map() much slower than for loop

henryjw profile image Henry Williams ・1 min read

I was working on some coding challenges when I got the sudden urge to test which approach was faster. For an input size of 1 million numbers, Array.map() takes about 2,000ms, whereas a for loop takes about 250ms. Any ideas why?

const INPUT_SIZE = 10 ** 7
const input = []
for(let i = 1; i <= INPUT_SIZE; i++) {
    input.push(i)
}

const pow2 = value => value ** 2

console.time('map')
const mapResult = input.map(pow2)
console.timeEnd('map') // 1800-2000+ ms

console.time('loop')
const arrayResult = []
for(let i = 0; i < input.length; i++) {
    arrayResult.push(pow2(input[i]))
}
console.timeEnd('loop') // 200-300ms

I always assumed Array.map() would be faster since it's a built-in function, but it looks like I was wrong.

Test 2

So after thinking about this for a while, I decided to perform a more fair comparison: Array.forEach() vs for loop. The results were that Array.forEach() is still slower, but not by as much as .map() (550-700ms).
My guess is that .map() performs some additional logic that slows it down significantly compared to a raw for loop.

Edit: I'm aware that this isn't exactly a practical scenario as we shouldn't be processing this much data using Javascript. This scenario is for theoretical understanding and discussion.

Posted on Apr 28 '19 by:

henryjw profile

Henry Williams

@henryjw

Software developer that really needs to get out more.

Discussion

markdown guide
 

This actually is a lot slower since mapping an array will create a copy of each value in order to not modify the original array.

Since a for loop does not copy the values but rather just accesses them using their index, it is a lot faster.

This peformance difference is only noticable when you have a large amount of data. For smaller amounts of data, it's better to write code which feels more natural to you, which may explain why map is used so commonly.

 

Thanks for the perspective. I'm going to try out the same test with creating a copy of each value in the for loop

 

Hi Henry,

Thanks for posting this and doing a test. It's really difficult to truly test out timing of code utilizing timestamps. I recommend the two resources below to better test, because in most cases, the performance of our code is very difficult to measure properly. I'd love to see the results of doing it with a proper test for sure, and how often one has a use case for 1 mill rows of data, since it would be really helpful for us :).

Benchmarking code requires quite a bit of stats and has many factors that are hard to bench mark without a library.

I'd recommend using benchmarkjs.com/ to do your bench marking, and potentially read github.com/getify/You-Dont-Know-JS... to better understanding the proper way to do benchmarking.

I hope that helps!

 

Thanks for the recommendations. I'll definitely check out You Don't Know JS.

 

It is slower because it has to create / initialise the callback function passed to it for every item.

There might be other reasons too

 

As you say, and i want to add something, the map tool returns you an array with the result of every element through the callback, if you don't want this you shouldn't use it.

 

But isn't that essentially what the for loop is also doing?

Correct. However, you should avoid using the for loop in general, because it will iterate over every property of the item passed to it including things which you might not want to iterate over (like a for in loop would do).

Alternatives to for include: forEach, for of, map etc

 
 

I put your code in a function and i get a perfomance hit in first call and after that its faster
First call in node 11.14.0:
loop: 270.822ms
map: 1293.307ms
Next calls in node 11.14.0:
loop: 366.816ms
map: 259.317ms
undefined

test()
loop: 304.949ms
map: 76.464ms
undefined
test()
loop: 290.823ms
map: 76.344ms
undefined
test()
loop: 293.326ms
map: 73.094ms
undefined
test()
loop: 288.508ms
map: 77.012ms

In chrome i dont get any notable performance hit by using map instead of loop with these code.

 

That's interesting. I going to try that.

 

You can also speed up for loop: allocate array with 1M elements and in for loop assign values.

 

Makes since, array.map calls a callback in a loop, then it's got to coordinate the callback with finishing its execution before it can move on to calling the callback again.

Them more code executions you have to do at the machine level, the slower the code will run.

 

Alternatively, for...of loop is another thing you should look into rather than conventional for loop.

 

Well if you consider the map acting as a function on each element, it's also having to create a new stack frame for each iteration.. a lot slower.