Iterating over Objects in JavaScript Quickly

I've been working with a bunch of people to help them get their code to trace (i.e, go really fast in Firefox), and one of the common anti-patterns I see, especially with people writing WebGL code, where they have to keep track of large numbers of objects in a scene, is the use of for...in vs. regular for loops.  This is one of those things that everyone knows not to do, so they never mention it, and new developers never get told it's bad.  Well, it's bad.  And it bears repeating.

One of the ways I like to get around this problem is to keep a separate array of key values, so you can loop across the array without iterating across object properties directly.  I wrote a little test that you can try running to see the effect.  Here is the code:

var items = {};  
var keys = [];  
  
for (var i=0; i<1000; i++) {  
  items[i] = i;  
  keys.push(i);  
}  
  
function forIn(times) {  
  for (var t = 0; t < times; t++) {  
    var total = 0;  
    for (key in items) {  
      if (!items.hasOwnProperty(key)) {  
        continue;  
      }  
      total += items[key];  
    }  
  }  
}  
  
function forLoop(times) {  
  for (var t = 0; t < times; t++) {  
    var total = 0;  
    for (var i=0, il=keys.length; i<il; i++) {  
      total += items[keys[i]];  
    }  
  }  
}  
  
function test(func, times) {  
  var startTime = (new Date()).getTime();  
  func(times);  
  return (new Date()).getTime() - startTime;  
}  
  
document.getElementById('for-in').innerHTML = test(forIn, 5000);  
document.getElementById('for-loop').innerHTML = test(forLoop, 5000);  

For me on my Mac, almost in any browser I choose, it takes between 1 and 058 and 500 ms to do these 5,000 iterations across the regular array. However, using a for...in loop across the object's properties takes between 1.3 and 3.8 seconds for 5,000 iterations.

The other thing I like about keeping my own list of keys is that I can have various lists, maybe one is sorted, one defines a subset of things I often need, etc. And, if you do a bit more work you can swap out the use of Array for a Typed Array if the browser supports it, making your loops go that much faster again.

Update: thanks to Wladimir for catching my typo items.length vs. keys.length

Show Comments