Is JavaScript optimization for loops really necessary?

I read that it is recommended to optimize loops in JavaScript not to read the length attribute of the array of each iteration in the loop header .

So, we must do the following:

var names = ['George','Ringo','Paul','John']; for(var i=0,j=names.length;i<j;i++){// Read array length once and assign it to a variable doSomeThingWith(names[i]); } 

instead of this:

 var names = ['George','Ringo','Paul','John']; for(var i=0;i<names.length;i++){ doSomeThingWith(names[i]); } 

However, I created a small test file to compare the two methods, but sometimes the first case was faster, and sometimes the second.

Which version would you recommend?

+15
source share
8 answers

Firstly, I have to say that this answer was written in 2011, and all this changes over time (as browser interpreters optimize more and more things), so if you really want to know the current state of the world, you need to run tests on current browsers.

Run your own jsperf test on any version of IE. There you will see the constant difference between these two methods or many other old browsers. You apparently only ran it in Chrome, which is so fast and optimized that there is a slight difference between the two methods. In IE9 (which is most likely better than IE7 and IE8), a method that pre-caches length is 31% faster.

The jsperf test developed for this question gives quantitative results on this issue. In matters like this, you just need to go to jsperf to see what the real difference is, not so much speculation.

This shows the difference in the browsers I tried, which range from almost no difference to a pretty significant difference depending on the browser. There is practically no difference in Chrome. In IE9, saving the first length is almost 50% faster.

Now, does this speed difference to your scripts depend on the specific code. If you had a huge array that you often repeated, in some browsers there is a significant difference in the use of this form:

 for (var i = 0, len = list.length; i < len; i++) { // do code here } 

In a slightly different test case, when using live pseudo-arrays returned by some DOM functions, there was still a difference in speed, but not (I expected the difference to be greater on DOM pseudo-living arrays, but it is not).

In practice, I tend to use a shorter version (less typing) when I don't think my code section is critically high speed and / or the array is small, and I would use a longer version that pre-caches if I consciously think of speed or an array huge, or I do a lot of iterations over the same array.

There are a couple of other programming reasons for pre-caching lengths. If you will add elements to the end of the array during the loop, and you do not want the loop to repeat over these newly added elements, you NEED to preload the length and only iterate over the original existing elements.

 for (var i = 0, len = list.length; i < len; i++) { if (list[i] == "whatever") { list.push("something"); } } 

Keep in mind that browsers are constantly evolving and adding more and more optimizations, so the optimization, which shows great benefit in 2011, can essentially be built into a more modern browser in the future, so manual coded optimization is no longer needed. So, if you are trying to optimize something for today's performance, you need to test in today's browsers, you cannot just rely on what you read, which may be several years old.

+18
source

This tip has always been micro-optimization at best, and with all the work done at the speed of the Javascript engines, this is unlikely to be a tangible difference. Perhaps somewhere in a very long, very tight cycle this may matter, but I doubt it.

For some reason, programmers tend to focus on speed above all else, even if it's unreasonable. Think about correctness, then readability.

+12
source

I would recommend the second:

 var names = ['George','Ringo','Paul','John']; for (var i = 0; i < names.length; i++) { doSomeThingWith(names[i]); } 

because it is shorter and more idiomatic. You will never need to use the first unless you perform some absurd micro-optimization.

+5
source

Typically, caching the "stop value" of a loop (in your case names.length) is valuable if it is a calculated value. For the array in question, this is just a search, so you get little by caching it.

+5
source

Define "really necessary" .
If you loop an array of 4 elements, I donโ€™t think even IE will mind, but keep in mind that you may have to iterate over some dom elements; let's say you have a list ( ul ) with entries of 1.000.000 (or more) ( li ). I think declaring an extra variable will save you from checking the length property of this time. Maybe I'm exaggerating a little the millionth part, but I will look at the test results only at 10,000 li .
The optimized cycle was almost a hundred times faster than the โ€œnormalโ€ one.

My conclusion: optimize your loops ... it cannot harm you (or your code or your browser).

+4
source

I would recommend

 var names = ['George','Ringo','Paul','John']; var length = names.length; for(var i=0;i<length;i++){ doSomeThingWith(names[i]); } 
+2
source

2017 Updated Answer

You should use the optimized / best way.

In your exact example: it is so trivial that it does not matter. Even with a 50% performance difference, as pointed out by @ jfriend00, that means little. Processors (including current smartphones) can do millions of calculations per second. This means that the fraction of a millisecond is simply not registered by the user, which corresponds to what @Ned Batchelder posted.

However, coding should not concern you with what you can get rid of. However, as @DwB said, "... the stop value ... is only valuable if it is calculated." With this in mind, the following code gives an example of a time loss function to return a stop value. It becomes obvious how different the speed is. Multiply potential server weaknesses, complex client code, and other intensive computing, and you can improve user experience using best practices.

  var eCount = document.getElementById("loopCount"); var waitDiv = document.getElementById("waitDiv"); var runButton = document.getElementById("runButton"); var interCount = eCount.value.replace(/\D/g,''); var names = ['George','Ringo','Paul','John']; eCount.addEventListener("input", function(){ var value = parseInt(this.value.replace(/\D/g,'')).toLocaleString(); this.value = value.toLocaleString(); }); function runLoop(){ interCount = eCount.value.replace(/\D/g,''); waitImg(true); setTimeout(function(){ var cachedTime = loopTest("cached"); var inlineTime = loopTest("inline"); document.getElementById( "cached" ).innerText = cachedTime+" Cached"; document.getElementById( "inline" ).innerText = inlineTime+" Not Cached"; waitImg(false); }, 100); // delay to allow update of DOM with waitimg gif } function loopTest(meth){ var worthlessVariable = 0; var t0 = performance.now(); if( meth == "cached" ){ for( var i = 0, len = busyCalulations(); i < len; i++) { worthlessVariable = i; } }else{ for( var i = 0; i < busyCalulations(); i++) { worthlessVariable = i; } } var t1 = performance.now(); return (t1 - t0); } function busyCalulations(){ // garbage math to simulate doing something // it returns interCount after some pointless math var limit = Math.floor(Math.random() * 20) + 20; return interCount*(limit*names.length)/(limit*names.length); } function waitImg(txt){ // display wait timer if (txt === true){ waitDiv.style.visibility = "visible"; runButton.style.visibility = "hidden"; }else{ waitDiv.style.visibility = "hidden"; runButton.style.visibility = "visible"; } } 
  <h1>Loop Tester</h1> <form onSubmit="return false;"> Loop Length <input id="loopCount" type="text" value="100,000"><br> <br><br> <button id="runButton" onClick="runLoop();">Run Test</button> <div id="waitDiv" style="visibility: hidden"><img src="https://i.stack.imgur.com/5qXc3.gif"></div> <br><br> </form> <div><p>Times are in milliseconds</p> <div id="cached"></div> <div id="inline"></div> </div> 
+1
source

See this article for optimizing JS loops.

So, a simple solution for you would be the following:

 let arr = ["a", "b", "c", "d", "e"] let i = arr.length while(i--) { callFn(); } 

The code above will run faster compared to other conventional looping methods such as

 for(let i = 0; i < arr.length; i++) {} 

Because the above code should retrieve arr.length at each iteration.

0
source

Source: https://habr.com/ru/post/1438607/


All Articles