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.
Top comments (15)
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
loopHi 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 afor in
loop would do).Alternatives to
for
include:forEach
,for of
,map
etcExactly
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
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 infor
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.