JavaScript Performance: For vs ForEach
By Adrian Sutton
As part of exploring JavaScript performance, I started wondering if the particular method of looping made a difference to performance. After all, one of the most often repeated bits of advice is that JavaScript is much faster if you loop backwards through an array instead of forwards and the slow part of my code was a loop. Using jsperf.com I could set up a simple test case pretty quickly and easily: for vs forEach.
There are a bunch of variants on loops in that test and the results really surprised me:
Browser |
---|
Chrome |
Firefox |
iPad |
iPhone |
Safari |
Here’s that data in a graph for Chome and Firefox just to make it a bit easier to visualise:
Unsurprisingly, the performance characteristics vary quite noticeably between browsers. What was surprising to me at least was that the new [].forEach() is one of or the slowest method to iterate through an array – slower than implementing forEach yourself in JavaScript in most browsers (mobile Safari being the exception).
The other thing that stood out is that green bar in the middle, representing the ‘for loop, cached length using function.call’ which is the current method of looping I’m using because that what the libraries implement. The advantage of this approach is that it not only supplies each item in the array, it also gives the index and the full array as extra arguments and it allows me to specify an object to use for ‘this’ in the callback function. That’s all potentially very handy but I wasn’t actually taking advantage of it. Looks like switching to a custom ‘each’ implementation which uses the for loop with cached length approach should give a performance boost without making any other changes to the code so no sacrifice in maintainability.
Sounds great, but after making the change there was less than a millisecond difference in the actual performance – well within the margin for error for measuring time in JavaScript performance tests.
Lessons Learnt
- Use whatever for loop setup you want – it’s unlikely to affect overall performance in any noticeable way.
- It’s probably not worth adding code to detect if there’s a built-in forEach you can leverage – just use the JavaScript implementation you’d need on older browsers anyway.
The Remaining Question
It’s all very well to learn these lessons, but since I’ve done all of this playing around in my own time at home, there’s a very significant problem with the results: they don’t include IE1{#footlink1:1286622982581.footnote}. Since my real performance problems are worst on IE 6,7 and 8, I need to be running these tests there – it’s possible that changing the looping system really would yield performance gains in IE. I’ll have to try that out on Monday.
1 – I do have IE in a VM I’ve just been too lazy to fire it up. Of course, if you happen have IE ready to hand, you can go and run the tests yourself and jsperf.com will add that into the mix ↩