loading...

JavaScript does not cache array.length

akashkava profile image Akash Kava ・1 min read

Myth: array.length is cached by JavaScript Engine

I have seen many comments and posts saying that JavaScript VM caches array.length for optimization.

So following piece of code is not required...

for(var i=0,n = a.length;i<n;i++) {
    ...
}
Enter fullscreen mode Exit fullscreen mode

And this one is automatically optimized by modern compilers.

for(var i=0;i<a.length;i++) {
    ...
}
Enter fullscreen mode Exit fullscreen mode

Well this is a myth, compiler can optimize but only if the for loop does not call any other method and performs simple mathematical steps.

In above example,

function run(a, f) {

   for(var i = 0; i < a.length; i++) {
       f(a[i]);
   }

}

var a = [0,1,2,3];

run(a, function(n) {
   console.log(n);
   if (n == 2) {
      a.push(4);
      a.push(5);
   }
});
Enter fullscreen mode Exit fullscreen mode

The output should be 0,1,2,3 if engine caches array.length, but if you notice, the output is 0,1,2,3,4,5.

This means that a.length is read before every comparison.

Optimization is expensive

Source level analysis of script is an expensive process, if JavaScript engine would spend time on detect complex logic to decide whether to cache or not, it would slow down startup time.

Discussion

pic
Editor guide
Collapse
pentacular profile image
pentacular

Actually, it's pretty easy to do escape analysis and determine that a property can't change within a given region.

{
  let a = [1, 2, 3];
  for (let i = 0; i < a.length; i++) {
    foo(a[i]);
  }
}

Here we can see that a doesn't escape this block, and no operation here can affect a.length, so we can just substitute 3 for a.length.

We also don't need to do this when starting -- we can delay analysis until we determine that the function is sufficiently expensive to be worth optimizing.

Which means that this doesn't need to slow down start up time.

Which isn't to say that your javascript implementation does this, but it isn't particularly hard.

What you need to do, rather than speculate, is to profile.

Fortunately some nice people have done this for us already.

chart
stackoverflow.com/questions/959224...

So it seems that some implementations do make a.length almost as efficient as using a local variable, at least in some circumstances.

The take away message here is that you need to use a profiler to understand performance.

Collapse
akashkava profile image
Akash Kava Author

Well length is stored as a special field on object instead of key/value pair, it is kind of shortcut property. Analyzing escaping etc, all require some logic.

Profiler is not an ideal, writing better code is never harmful, it is good practice. We usually have millions of lines of code and you can't sit and profile thousands of different patterns unless you are paid millions of dollars for applications.

Collapse
pentacular profile image
pentacular

Length may be stored as a special field on some implementations, but it isn't required to be the case -- be careful not to confuse your favorite implementation with the language itself.

The problem with 'writing better code' is that what is better depends on many variables.

A profiler is a way to test what is better, and how much better, in a particular environment and with a particular workload.

This allows you to make decisions based on actual data rather than guessing -- it's often the case that the optimizations you think ought to matter just aren't important at all for how the code performs.

In the absence of profiling, I'll always recommend maximizing readability, since that's the most constant cost.