Your Javascript Loops Are Slowing You Down
Learn to Loop Responsibly
Lets imagine for a moment that you need to loop over a collection of items in your application. If you are like 90% of Javascript developers out there I’m pretty confident that your approach to doing so looks something like this:
Looks familiar right? I’m also guessing that your collection sometimes isn’t a direct local variable, but is probably part of a larger object like a view model or something similar:
Thus you might consider looping over the set of teachers above like so:
Unfortunately, as your application grows this format may end up biting you in the ass when it comes to performance.
So what’s so bad about that!? The problem is that when executing a Javascript loop, the loop comparison is calculated for EVERY iteration of the loop.
(The “loop comparison” being the highlighted section)
Most developers understand that the x < y part is calculated every time around, but most don’t consider that the calculation of finding the value of x and y themselves is also performed. That means, in the above example, that student.teachers.length is calculated each time we go through the loop. This is not a big deal when your collection is small or the number of hops from the root object to the list property we want is small, but when you start doing lots of iterations it really adds up!
Lets see what happens when the collection gets bigger and the distance from the root object to the list property grows like the spaghetti monstrosity we all seem to end up working on as code ages. I built a simple object like so that contains a list deep in the structure:
Then I filled the “h” array with 100,000,000 random integers (yeah probably not the average array size, but it helps illustrates the point)
Next I ran three loops over the collection with the following variations.
BAD: Loop #1 uses the loop comparison i < data.a.b.c.d.e.f.g.h.length which means we hop down the object chain and then find the length of the array each time.
BETTER: Loop #2 saves the h array to a local variable called hlocal so we don’t have to hop down the object chain, but we still calculate the collection length every time using the loop comparison i < hlocal.length.
BEST: Loop #3 saved the length of the array h to a local variable called len which means we hop down the object chain and calculate the array length exactly one time and end up with the simple loop comparison i < len.
Results
Chrome 39 & Firefox 32 : I was pleased to see that the looping differences had no effect on chrome or Firefox. From what I understand Chrome and Firefox do some optimization to prevent these types of issues so it was not much of a surprise.
IE 11: Here is where things break down. This probably comes as no surprise to most of us, but IE doesn't appear to do any optimizations for you and is incredibly slow even using the fastest loop format compared to Firefox and Chrome.
Performing the length calculation doubles the amount of time spent looping, and digging through the extra layers of that object is 10x slower! These numbers are coming from the latest versions of three of the most common browsers (sorry, I was too lazy to get Opera or Safari benchmarks) running on a high performance desktop machine. I’m sure you can imagine how a mobile device using slower hardware or machines running older browsers without the built-in Javascript optimizations could affect these numbers even more extremely.
The last thing I would like to point out is that the above tests were run over a static list of integers. Things can get much much worse with this fairly common pattern…
You’re looking at bringing an application to it’s knees pretty quickly.
In the real world most of us aren’t looping over gigantic data sets like this in Javascript but more and more web apps are moving processing to the client side in order to compete with the performance of their native app brothers. Part of that move may include bringing large data sets into the browser’s local storage which means looping over large data sets may become more likely in the future so start writing tight loops now and you may save your future self a whole lot of pain down the road.
Loop Responsibly. ☺