6x times faster loops in Javascript

Sanket KalekarSanket Kalekar
3 min read

Javascript is fast. Really fast - at least if it´s running in a modern browser. So, in general you should not care too much about performance. But when it comes to text processing, things might be worth a closer look:

  • are there impacts of the way we manipulate strings? Memory management can cause serious bottlenecks

  • Do the loops make any difference?

I really did not know, so I did some performance testing with interesting results that I want to share here.

Do some tests

My test case was quite simple: Add an "x" to each line of a text of about 4000 lines . Import of the file was done before measurement, so reading the text into a variable was not part of the test. I used the performance-API on chrome, which is intentionally a bit reduced in precision, but delivers reasonable results if you repeat your task often enough. In this case, I repeated the task 10.000 times.

So, this was my first code (count = 10000, 4625 lines):

for (n = 0; n < count; n++) {
      res1 = text.split("\n").map(line => line + "x").join("\n")
    } // Time 1 = 190ms, average 0.075 us/line

So, here we split the text into an array, convert the array and join the lines again finally. So we get the initial text with x added to every line. And performance is amazing! This are 46 Mio. text operations done in 0.19s, each operation was done in about 0,075 Microseconds on my fairly old machine.

But could we do better? Array manipulation might include some memory shifting. This was my second try:

for (n = 0; n < count; n++) {
      ar = []
      text.split("\n").forEach(line => ar.push(line + "x"))
      res2 = ar.join("\n")
    } // Time 2 = 178ms, average 0.071 us/line

Instead of map() I used array.push() to build the array, but this was only slightly faster.

The next try was to avoid join() by adding the string manually:

for (n = 0; n < count; n++) {
  res3 = ""
  text.split("\n").forEach(line => res3 += line + "x\n")
} // 82ms, average 0.032 us/line

This was a big jump: It seems, string concatenation is really fast, cutting the time by more than 50%.

But what about the loops? forEach does all the heavy lifting, so we should try it out:

for (n = 0; n < count; n++) {
    lines = text.split("\n"); res4 = ""
    for (i = 0; i < lines.length; i++)
      res4 += lines[i] + "x\n"
  } // Time 4 = 33ms, average 0.013 us/line

This was a suprise: The good old loop performs much better! Compared to the inital loop, this was 6 times faster! Amazing!.

But well, this looks a bit old fashioned, so how about the modern style? See the results:

This is for .. in

for (n = 0; n < count; n++) {
    lines = text.split("\n"); res5 = ""
    for (i in lines)
      res5 += lines[i] + "x\n"
  } // Time 5 = 172ms, average 0.068 us/line

and for .. of

for (n = 0; n < count; n++) {
    lines = text.split("\n"); res6 = ""
    for (line of lines)
      res6 += line + "x\n"
  } // Time 6 = 36ms, average 0.015 us/line

So, finally we are back in the winning row, but results are really surprising: Just changing the loop style can slow you down by a factor of 5-6.

There is absolutely no general rule. Things are much depending on the implementation details, and can be different on different browsers. But as you might see: It is worth to do some performance testing to get better results.

Thanks for diving into JavaScript performance optimization with me! Stay tuned for more updates here and on Twitter for programming tips and new learning! #javascript #programming #performance 🔥

1
Subscribe to my newsletter

Read articles from Sanket Kalekar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sanket Kalekar
Sanket Kalekar