38

I was browsing around and I found this:

var i, len; for(i = 0, len = array.length; i < len; i++) { //... } 

My first thoughts are:

  • Why he did that? (it must be better for some reason)
  • Is it worth it? (I assume yes, why else he will do it this way?)

Do normal loops (the ones that don't cache the length) check the array.length each time?

5
  • 3
    Caching the length is probably a bigger deal in older browsers that don't compile the code. If I remember, Chrome pretty well optimizes this away. Commented Dec 9, 2011 at 22:11
  • 1
    @RightSaidFred - Chrome doesn't optimize it away because it can't (the length could change inside the loop), but it's just fast enough that there isn't a big speed difference either way. Commented Dec 9, 2011 at 22:21
  • @jfriend00: Because it is compiled code, it would seem that Chrome could know if the Array is modified in the loop, and optimize if not. But I certainly agree that it's basically a moot point when it comes to Chrome. Commented Dec 9, 2011 at 22:22
  • @RightSaidFred - Maybe if there were no function calls in the loop and no properties with accessors in the loop and no methods on the array called in the loop, etc... But, it's pretty hard in JS to know what might or might not modify the length of the array indirectly. I think Chrome is just fast enough that these types of optimizations don't make as much of a difference as they used to. Commented Dec 9, 2011 at 22:25
  • @jfriend00: Yeah, I totally hear what you're saying. I've often wondered just how far Chrome is able to follow the code and optimize. The few times I've run code through an Advance Optimization in Google Closure Compiler, I was pretty amazed at the code it unraveled. Not sure how that plays in though. Commented Dec 9, 2011 at 22:56

6 Answers 6

30

A loop consisting of three parts is executed as follows:

for (A; B; C) A - Executed before the enumeration B - condition to test C - expression after each enumeration (so, not if B evaluated to false) 

So, yes: The .length property of an array is checked at each enumeration if it's constructed as for(var i=0; i<array.length; i++). For micro-optimisation, it's efficient to store the length of an array in a temporary variable (see also: What's the fastest way to loop through an array in JavaScript?).

Equivalent to for (var i=0; i<array.length; i++) { ... }:

var i = 0; while (i < array.length) { ... i++; } 
Sign up to request clarification or add additional context in comments.

3 Comments

the problem is the property lookup. In order to calculate expression B, its necesarry to have one lookup on the object/Array for each iteration, that is slower than having a lookup with the local scope. Its always the fastest possible way to lookup something if it can get found in the local scope, that is why you would store the length in the current scope by using var foo =.
The difference is very dependent on the browser. In older browsers, caching is more effective. For comparisons, have a look at: jsperf.com/caching-array-length/4
@RobW: certainly yes. new'ish js engines will optimize object lookups like a lot. The engine will have internal lookup hashes to access a property. So yes, this micro optimazation will have much more effect on oldish browsers (=== IE<9)
13
Is it worth it? (obviously yes, why else he will do it this way?)

Absolutely yes. Because, as you say, loop will calculate array length each time. So this will cause an enormous overhead. Run the following code snippets in your firebug or chrome dev tool vs.

 // create an array with 50.000 items (function(){ window.items = []; for (var i = 0; i < 50000; i++) { items.push(i); } })(); // a profiler function that will return given function's execution time in milliseconds var getExecutionTime = function(fn) { var start = new Date().getTime(); fn(); var end = new Date().getTime(); console.log(end - start); } var optimized = function() { var newItems = []; for (var i = 0, len = items.length; i < len; i++) { newItems.push(items[i]); } }; var unOptimized = function() { var newItems= []; for (var i = 0; i < items.length; i++) { newItems.push(items[i]); } }; getExecutionTime(optimized); getExecutionTime(unOptimized); 

Here is the approximate results in various browsers

 Browser optimized unOptimized Firefox 14 26 Chrome 15 32 IE9 22 40 IE8 82 157 IE7 76 148 

So consider it again, and use optimized way :)
Note: I tried to work this code on jsPerf but I couldn't access jsPerf now. I guess, it is down when I tried.

1 Comment

You should include the version of Firefox and Chrome. This is a very detailled JSPerf: jsperf.com/caching-array-length/4
1

I always thought in JavaScript length was just a property of the array object, pre-calculated by previous array operations - creation, addition, removal - or overridden by the user, so you're just looking up a variable anyway? I must admit I had just assumed that because of the lack of parenthesis, but looking at the MDN page for array.length, it seems to say the same thing.

In languages where length is a method or length is calculated by a standard library function, then you should pre-calculate the length before running the loop so The array isn't calculated every iteration, particularly for large datasets. Even then, in modern high level languages like Python, len() just returns the length property of the array object anyway.

So unless I'm mistaken, the complexity is just O(1), and from that standpoint, even if the variable were slightly faster than a property to lookup each pass, it wouldn't be worth the potential trouble of creating/reusing additional variables outside of the protective for loop scope.

However, I suspect that in this case the reason the example's programmer chose this approach is simply just a habit they picked up in another language and carried forwards JavaScript.

Comments

1

One reason to do this would be to iterate only over the initial length of an array while new elements are being added. For example, this loop appends a copy of an array to itself, turning [0, 1, 2] into [0, 1, 2, 0, 1, 2]:

const initialLength = items.length; for (let i = 0; i < initialLength; ++i) { items.push(items[i]); } 

If we did not store the length and instead compared i to items.length on every iteration, it would cause an infinite loop.

Otherwise, if you find loops written like this for no apparent reason, it is probably a naive attempt at optimization. Modern JavaScript engines know how to optimize common tasks such as array iteration, so this is entirely unnecessary.

Comments

0

Yes Its check the array.length every time, but if we don't want to run our loop for increased array then, in that case, we can use forEach method.

forEach is a javascript in build method which is does like for loop, but forEach only iterative the elements in an array which are before the loop start.

Let's understand this from below snippet:

array = [1,2,3,4] for(i=0;i<=array.length;i++){ console.log(array[i]); array.push(array[i]+1); }

output like 1 2 3 4 5 6 ...so on (infinite) while its checking array.length each time

let's check with forEach method

array = [1,2,3,4] array.forEach((element) => { console.log(element); array.push(element+1); }) console.log("array elements after loop",array);

it only processes for 4 elements which are present in array before iteration start.

**but in forEach case, it will affect on array.length if we pop out the element from array.

lets see this by an example:

array = [1,2,3,4] array.forEach((element) => { console.log(element); array.pop() }) console.log("array elements after loop",array);

Comments

-1

Here are a number of performance tests for different approaches

http://www.websiteoptimization.com/speed/10/

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.