When coding JavaScript, I find myself using the for
loop fairly often. Recently, when I coded, then re-coded these drop-down menus, during the re-code I ran my JavaScript/jQuery through JSLint using the option called “The Good Parts”.
I don’t know a whole lot about JSLint, but I figured that would be a pretty good way to ensure the code was efficient, relatively future-proof, and easy to maintain (i.e. it uses best practices).
The info JSLint provided, as well as other stuff I’ve read in the past, got me thinking about the simple JavaScript for
loop and how it’s customarily written.
How It’s Typically Written
I think it’s safe to say that most beginner to intermediate JavaScript developers will write their for
loops like this:
var anchors = document.getElementsByTagName("a"); for (i=0;i<anchors.length;i++){ // do some stuff here }
I included an extra line to collect some DOM elements to iterate over, but the loop is really what we’re focused on here. Even though this code will work just fine, how can it be improved? Well, JSLint as well as best practices for high performance JavaScript will assist us to make some small, but important improvements.
Fix the Spacing
That small example of code produces 11 error messages in JSLint using the option “The Good Parts”. One of the things JSLint will often point out is the lack of spacing around your operators. So let’s fix the spacing. Here’s how our code looks after correcting all the spacing issues:
var anchors = document.getElementsByTagName("a"); for (i = 0; i < anchors.length; i++) { // do some stuff here }
Technically, I didn’t need to put a space after the semicolons, but I did it anyhow to aid readability. In addition to proper spacing around the operators, JSLint also requires a space between the closing parenthesis and the opening curly brace. All these spacing issues are, from what I understand, to help avoid using confusing code that’s prone to accidental errors or code in which errors are hard to spot.
Localize Your Variable
After fixing the spacing issues, we can now focus on another error presented by JSLint: the global variable i
. Any variable not defined using the var
statement in JavaScript is global in scope. This is bad practice, and it can be easily overlooked inside of such a commonly-used bit of code. So let’s make our variable local using the var
keyword. We could do this a couple of ways, but the following method will suffice to make JSLint happy:
var anchors = document.getElementsByTagName("a"); for (var i = 0; i < anchors.length; i++) { // do some stuff here }
Now JSlint only gives us one remaining error. (Well, technically, this code will give two other errors: The document
global and the empty block, but that’s not a big deal in this illustrative example).
Don’t Use the Increment Operator
This is something that I was surprised to see. I haven’t yet read Crockford’s book so I don’t know if there’s more to this than what’s explained on the JSLint instructions page, but here’s what it says about the increment (++) operator:
The ++ (increment) and — (decrement) operators have been known to contribute to bad code by encouraging excessive trickiness. They are second only to faulty architecture in enabling to viruses and other security menaces.
My guess is that using an increment operator in a harmless for
loop is not going to cause much of a problem for you. But who am I to question? So what is the alternative? Well, the increment operator is just a way of saying “add 1 to my variable”, so let’s make JSLint happy by doing just that:
var anchors = document.getElementsByTagName("a"); for (var i = 0; i < anchors.length; i += 1) { // do some stuff here }
I really don’t know if this is the best and/or only way to do this, or if this is even necessary in a for
loop, but it gives us the same result and JSLint likes it.
Now there are no significant errors in this seemingly harmless bit of code. But there are two more improvements that can be made that JSLint doesn’t warn us of.
Don’t Calculate the Length on Each Iteration
As the code is now, the length of anchors
is calculated on each loop iteration. In a large application, and with large values and multiple loops, this can contribute to performance issues. So although in many small instances this might not matter, it is best practice to try to cache values before using them. So we can alter the code to look like this instead:
var anchors = document.getElementsByTagName("a"); for (var i = 0, j = anchors.length; i < j; i += 1) { // do some stuff here }
Now the value gets calculated only once, and is stored in the variable j
. I certainly have to thank the commenters in some of my previous JavaScript articles for pointing out this improvement in my loops.
Decrement the Value Instead
Assuming that you don’t care about the order in which the collected elements are looped through, you can evidently improve the performance of your loops by decrementing the value instead of incrementing it. Here’s how the new code will look:
var anchors = document.getElementsByTagName("a"); for (var i = anchors.length - 1; i >= 0; i -= 1) { // do some stuff here }
Now the different parts of the loop’s instructions have been reversed and we’ve even eliminated the use of a second variable, since we know that we’re just going down to 0. Of course, you might have a case where decrementing your loop would not work, so this is just something to consider should the situation allow for it. Notice also that I’m subtracting one from the starting value and letting the loop go down to zero, to account for zero-based indexing.
Final Thoughts
So that’s it, there’s five practical improvements made to a simple for
loop, and more importantly, some underlying principles that can help you to write cleaner and more efficient code on a larger scale.
As a side point, there aren’t many examples online or otherwise that will present a for
loop using the tips described above, but I think it would be good if most developers adopted these practices if they do indeed contribute to better performance, readability, and maintainability.
I should point out — as I often do when I write about JavaScript — that I don’t consider myself an expert in this area, so if you have any corrections or supplementary information to contribute to this topic, please do so in the comments. And by all means, do the necessary research before you take my word as gold. I’m still learning, and I’m happy to correct any mistaken views.
Your last example for “Decrement the Value Instead” will cover values from 1 to N instead of 0 to N-1.
Kudos sir. That bugged me too :/
My preferred way is:
That’s how is I’m used to do it in other languages too, although I usually don’t declare the
i
variable in-line like that. The reason I putanchors.length
in a variablej
is that in PHP it allows for faster code execution and it is something that stuck. I must honestly say I never did tests in JS. My guess is it won’t matter that much since you’re accessing a property value and not executing a methodI do not agree about the increment and decrement operators. Bad or good architecture is up the programmer and IMHO there is nothing tricky about
i++
or++i
what about :
it spares one evaluation
Very nice!
– cached & localized variable
– tiny code
I’m sticking with this method from here on out! :)
This is a nasty way to do this and is guaranteed to confuse future developers who look at your code. By putting the decrementer in the evaluation statement, you’re counting on javascript interpreting the numbers 0 and below as “falsy” values in order to break out of the loop.
The idea that eloquently written code might, “confuse other developers” has always been laughable to me. A fellow dev should smile and learn, not whimper.
JavaScript is an insanely powerful language that all too often gets stripped back to inferior, over simplified structures because, “too confusing”. Such a shame.
For those still concerned, there are projects like http://eder.us/projects/jbasic/ :p
Hello,
I’ll stick to the “i++”, and I have suggestion for the “Decrement the Value Instead” example. Wy not use “while” instead ? e.g.
http://jsperf.com/for-loop-vs-optimized-for-loop/17
You’re right! There is a slight performance advantage to the while loop on most browsers (at least on Win8, my tester). It’s most noticeable in Chrome 24 and IE 10.
(or maybe I spoke to soon, more results are coming in)
It is always best to cache the iterator (anchors.length) due to the reasons given above, though it is especially important when dealing with HTMLCollection objects (as returned by document.getElementsByTagName).
This is because an HTMLCollection is live, i.e. it is updated whenever the DOM itself is modified – thus if you were to execute some code within the loop body which modified the anchors in the DOM, you could have undesirable behaviour. At worst case, if you were creating a new anchor with each iteration, the length of the collection would increase if you did not cache it – potentially causing an infinite loop.
Good article, but there’s some important distinctions here. You say:
That’s not exactly correct. The i++ syntax says “execute this statement, *THEN* add 1 to my variable”. (And the ++i syntax says “add 1 to my variable, *THEN* execute this statement”.
Sounds like nitpicking? Not exactly. In the context of your code, it doesn’t make much difference (the part of code after the second semi-colon is executed after each iteration). However, consider the following:
Note the number of iterations can differ with implementation… This is confusing because many people read “i++” and “++i” as fundamentally the same (similarly “i–” and “–i”), but they aren’t.
Further, the values of i are different in different implementations (even amongst the ones with same number of iterations). You did mention the caveat about whether or not order matters, but in your example, the values of i (that we loop through) are different, and why are you iterating through an array if you’re not using i as an index into the array?
What about
?
http://www.slideshare.net/nzakas/speed-up-your-javascript
Slide 55
Haven’t tested them for speed comparison by myself, though.
This is unpredictable behaviour because if you add any variables to the Array prototype, you will include those in the loop. As it is, I believe i will equal “length” at some point, instead of 1, 2, 3… etc.
How about
Way more simpler, no?
I’m with the last two guys. Javascript’s for in and PHP’s foreach are the loops I use most often.
+1 to @jpvincent and @Olivier Laviale.
On element collection/arrays that can’t contain ‘falsy’ items, my favorite way is:
Which is like a “foreach” and still preserves the order of elements.
Since in my University, we were taught to use the “++” increment for loop, and this is the first time I see that “+=” can replace “++”. Awesome knowledge Louis.
I’ve always found
to be readable and correct (so long as i is signed in a language that supports unsigned types)
This was slightly higher performance in low-level code (C) when cache lines weren’t a factor, as machine code produced can be something like:
LOOP_START :
decrement;
jump-if-less-than-zero END_LOOP;
loop contents ;
goto LOOP_START;
END_LOOP :
which is simpler than the comparisons and jumps required otherwise.
I got into this habit 20 years ago, though. No idea whether this holds when CPU cache lines are put into the mix. Optimizing JS compilers like V8 might be able to demonstrate a microbenchmarkable improvement (or not)..
like @jpvincent, though I tend to stick what i’m checking against outside the for loop declaration:
var i = array.length;
for ( ; i–; ) {
// do some code
}
I have question related to JavaScript Optimization.
Whenever web page is rendered , its all css + script files are also loaded hence effect bandwidth etc.
If I code JavaScript in meaningful manner ( popup.js serve popup .. slideshow.js serve slideshow etc etc) then on each round trip it effects performance .. And if I write whole JavaScript code in single file ( messy code ) it will be difficult for other to understand the flow of code etc … and if I myself review the code after 3-4 month it will be strange for me too.
So how to optimize such issue ..
I think the best way is to put as much as possible in one file, but build your script in abstracted modules or functions.
For example look at the code for my Ajax drop-downs, at this link below:
http://www.impressivewebs.com/demo-files/mega-drop-downs/js/general.js?ver=2
It’s all namespaced and there are specific functions for each action, to keep it nice and organized. I’m by no means a top expert in this area, but I find it’s pretty easy to maintain it this way, rather than using code forking that’s not as organized.
Actually caching a length of collection is not for performance.
It’s for correctly working your code, James Shuttler aleready said.
And
is not good style for javascript.
Because js has fuction scope.
You should write like this.
Yep, I normally do it that way nowadays. I should probably update the article to reflect this. Thanks.
Thanks for the detailed and organized help!
I am surprised to see the notation about ++ being a ‘bad coding practice’ ..
re: “The ++ (increment) and — (decrement) operators have been known to contribute to bad code by encouraging excessive trickiness. They are second only to faulty architecture in enabling to viruses and other security menaces.”
This is inaccurate… for most coding styles of ppl who write i++ i guess it doesn’t matter.. what *does* matter is that 99% of ppl use i++ in their loops. ‘THAT’ is a bad coding practice! It should have been taught in school to use ++i (the pre-increment) form. ‘Pre-increment’ has fewer machine instructions to achieve (it does not have the ‘store’ the original value before incrementing it’). Maybe the newer chips have eliminated the step, but i don’t think so.. If you want to maximize a loop do some research on ++i pre-increment at the machine code level and see what the ‘current’ science of it is (in terms of assembly / register instructions).
Your argument loses a lot of its credibility when you abbreviate “ppl”.
Thanks for this. I’ve been curious about ++ vs — for a while now. Oh, I also want to point out that the article you linked to is actually originally from StackOverflow (http://stackoverflow.com/questions/3520688/javascript-loop-performance-why-is-to-decrement-the-iterator-toward-0-faster-t). Websites like the one you linked to like to steal their content.
Nice catch Levi, I’ve changed the link to the SO thread instead. I must have found that via a Google search and didn’t bother looking at it carefully enough. Thanks for pointing it out.
Interesting note: ++ is actually faster in Chrome, and += is faster in IE10.
8)
http://jsperf.com/loop-inc-test
very nice, ill start writing my for loops differently now
try this:
var i = 0,
len = arr.length;
for (i; i < len; i++) {
//do something
}
I could be wrong about this but I thought lenght was a property not a function so what are you actually calculating? My thoughts are the the length property is already a memory location, so creating another variable and assigning a value to it such as the length property is actually a pointer to the original location where the length property is stored so you are not gaining anything except using more memory? Just trying to get educated.
This post covered everything regarding iteration. Thanks for detail level explanation.
As a trainer and developer working over ten years with JavaScript. I’ve seen a lot of silly mistakes, quite some tough mistakes and a couple of whoa-what-are-you-doing mistakes, but suggesting not to use
i++;
anymore is just silly. If you work with a professional team of developers who know their stuff and thus know the language they’re programming in, doing an increment is perfectly fine.It’s the same with the
for
-loop where you declare the variable up front, why would you do that? Again, know your stuff and stop protecting you and your teammates from hypothetical mistakes. It’s time-consuming and quite frankly, belittling and insulting to your team. It’s -silly-. Crockford’s coding style is not holy.Here’s a speakerdeck which has this opinion and much more: https://speakerdeck.com/anguscroll/the-politics-of-javascript
When you say “Don’t Calculate the Length on Each Iteration” and “As the code is now, the length of anchors is calculated on each loop iteration” you’re totally wrong.
Doing this:
for (var i=0; i<anchors.length; i++) {...}
does not calculate the length at all. The length property of an object (in this case an array) is only a number. It isn’t calculated, it’s stored in the object itself, so reading the length property is exactly the same thing as assigning it to a variable and then reading it from that variable (which would only be a waste of memory).
Yes, the word “calculated” is wrong – but I’m sure what he means is that it is RESOLVED (not calculated) on each iteration (because of the dot). It’s faster to first store it into a variable.
Old post, so I definitely used the wrong wording (but I’d probably make such mistakes today too).
I agree with James, as I understand, it’s faster to store it in a variable. In fact, here are a few JS Perf tests:
http://jsperf.com/caching-length-vs-not-caching-length
http://jsperf.com/array-length-vs-cached
http://jsperf.com/arrays-caching-length-or-not
I created the first one, just now, but the others are probably more reliable. From my running of those, it looks like the version of the code that caches the length is always faster. I haven’t seen the non-cached version win the test yet.
first of, thanks for the article. even if it is confirmed as outdated, to my old programming skills that was an interesting read nevertheless. and, more importantly, thought provoking.
now for the non-properly-interrogation-marked questions… (lack of text editing)
http://jsperf.com/array-length-vs-cached actually gave me ( Chrome 56.0.2924 / Mac OS X 10.11.6 ) the cached version 26% slower (3,763,040 ±13.50% vs 5,016,621 ±12.13% from the not-cached version). twice. but both of the other 2 links and http://jsperf.com/array-length-vs-cached/54 gave me cached version running faster while non-cache would go anywhere from 20% to 66% slower. and, on the second run, there was basically no difference in any of them. every test was “fastest”. oddly enough, cached with –i and just 2 for arguments was 13% slower.
looks like, at least nowadays, there’s more to it than just “cached is faster”. I think it comes at no surprise that newer js engines would eventually optimize that one out.
also, jslint don’t even recognize
for
anymore:maybe those this whole article needs to be re-thinked. I sure need to do it for my own, as I just learned of jslint today.
ps: sad those comments don’t allow markdown! too lazy to html. ;P
Nice article. I enjoyed the reminder of your last 3 points.
Of course, these performance differences will rarely be felt, it’s nice to have them in one’s back pocket for when it really does matter. Readability generally triumphs.
In the section “Decrement the Value” ..
It looks like here is a typo where the number 0 has been written as a lower case o instead.
“..just going down to o”.
I wonder if that performance boost would be be any different if one substituted
i >= 0
with ai
, where the index is adjusted appropriately to stop at 0.Is checking for a falsey value of plain
i
any different than checkingi !== 0
ori > 0
.Hmmm, actually, the “0” is really a zero. It’s just that the font makes it look very o-ish. The code examples use a different font, so the zero has a line through it, like it should.
How can you optimize the given JavaScript for loop code snippet to improve performance by avoiding the calculation of the anchors’ length on each iteration?