High performance JavaScript – part 1

When building an application which requires fast array computation (e.g. analysing video/sound stream in real time, drawing on canvas) performance improvement becomes a very important part of the development.

There are several things we can focus on:

This time we will check which kind of loop we should choose to get the best performance.

Test!

We’re going to test following code on Firefox 41 and the newest Microsoft Edge 20. Result is an average execution time of code running on both browsers.

Sample data:

var arr = [];
for (i = 0; i < 100000; i++) {
  arr[i] = 'Value' + Math.random();
}

Test code:

// simple for loop
for (var i = 0; i < arr.length; i++) {
   arr[i];
}

// for loop with cached variable
for (var i = 0, l = arr.length; i < l; i++) {
   arr[i];
}

// while loop
var i = 0;
var len = arr.length;
while (i++ < len) {
  arr[i];
}

// reverse while loop
var i = arr.length;
while (i--) {
  arr[i];
}

// for..in loop
for (var i in arr) {
   arr[i];
}

// for..of loop
for (var i of arr) {
   i;
}

Results for a dense array containing 100,000 items:

  • basic for loop: 87.44ms
  • cached for loop: 85.9ms
  • while (i < len) : 86.48ms
  • while (i–): 59.04ms
  • for..in: 85.69ms
  • for..of: 79.05ms

What’s interesting, using block-scoped variables (let keyword) gives us better results:

  • basic for loop: 33.64ms
  • cached for loop: 22.84ms
  • while (i < len) : 41.97ms
  • while (i–): 70.71ms
  • for..in: 47.11ms
  • for..of: 50.05ms

Probably it’s becase of the way how JS compiler is allocating memory for block-scoped variables.

It’s getting even more interesting when we test loops on sparse dataset:

var arr = [];

for (let i = 0; i < 100000; i++) {
  if (Math.random() < 0.2) {
    arr[i] = 'Value' + Math.random();
  }
}

Results:

  • basic for loop: 43.11ms
  • cached for loop: 33.36ms
  • while (i < len) : 61.06ms
  • while (i–): 52.16ms
  • for..in: 10.55ms
  • for..of: 53.91ms

The reason why for..in loop is fastest is somehow surprising, but when we think about the way how this kind of loop works, it makes sense. For loop is going though all keys in an object. If array is sparse, there will be fewer indices to traverse.

Next

Next time I’m going to talk about low level binary arrays, how to do C-like memcpy() in JavaScript, and how it can hugely speed up computation process.

 

Photo by KhaOS: https://commons.wikimedia.org/wiki/File:Jenson_Button_2006_Canada.jpg