Speed and memory benefit from declaring variable outside JavaScript loop?

Go To StackoverFlow.com

3

There are similar questions for C#, but we didn't see any for JavaScript.

Is it accepted practice to declare variables inside a loop?

Assume a loop of 200 iterations.

Is there a performance imperative (memory and speed) to using sample 2 over sample 1? We're using jQuery to loop. It improves code readability for us to keep the var inside the loop, but we'll switch if it's not a best practice or will result in materially slower performance or higher memory usage.

**Sample 1:**
$(this).each( function() {
   var i = $(some_div).clone();
   *** edit i ***
   $(another_div).append( i );
});



**Sample 2:**
var i = null;
*** edit i ***
$(this).each( function() {
   i = $(some_div).clone();
   $(another_div).append( i );
});
2012-04-04 23:51
by Crashalot
Why don't you measure this - Sergio Tulentsev 2012-04-04 23:53
@Crashalot: In sample 1, variable is created at each iteration. In sample 2, variable is reused. Have you done some performance tests - Marat Tanalin 2012-04-04 23:53
No, we were curious to hear best practices since this must be an established pattern. We assume there is a performance gain because the var is reused, but wondered if there were significant advantages. It's simpler to read the code if the vars are inside the loop, but if speed and memory performance requires declaring outside, then we will - Crashalot 2012-04-04 23:56
Each implementation could be different. For all you know without further research any given interpreter could optimize it on the fly and remove any penalty - Rig 2012-04-04 23:56
One lexical scope lookup vs non closed over variables. I would imagine that the difference would be negligible and vary wildly between browsers. Probably not worth the theoretical performance gain. Write what makes sense - James Holmes 2012-04-05 00:07
Your two samples are not equivalent - gilly3 2012-04-05 00:10
If performance is an issue you'll get a much more significant improvement by replacing the .each() loop with a conventional for loop. Note that your sample doesn't need the i variable at all: $(anotherdiv).append($(somediv).clone()); - also, without having tested it, I'd expect a performance improvement if you declare variables outside the loop for $(anotherdiv) and $(somediv), rather than creating new jQuery objects in every iteration - nnnnnn 2012-04-05 00:20
Each already passes the index to the callback. See the API doc - AutoSponge 2012-04-05 00:35


3

Sample 1 (variable inside) is faster: http://jsperf.com/variable-outside-faster

But the difference is not worth enough to care about.

2012-04-04 23:58
by binarious
wow, this is cool! how did you find this site - Crashalot 2012-04-05 00:00
we're confused. how is inside faster? isn't it executing an extra operation (declaring variable)? we're also curious on the effect on memory - Crashalot 2012-04-05 00:01
@Crashalot I've seen Paulirish.com using this, I got it from him. I can't explain why it is faster, just tested it - binarious 2012-04-05 00:02
Heh, you were faster than me in creating this. Look at "Shorten Scope Chains" in this article for an explanation - sirhc 2012-04-05 00:05
Declaring a variable isn't an extra operation. Chrome, for instance, compiles that JavaScript to native code before executing. That means it will pre-allocate some memory to the function. I believe when it tries to resolve the variable name, having it in the same scope speeds up the lookup, so the first code ends up faster. But this is just my guess. Anyway, that wouldn't be necessarily true in other implementations, be it other browsers or JavaScript embedded in other environments (JVM, .NET CLI etc) - mgibsonbr 2012-04-05 00:06
@mgibsonbr, thanks for the clarification! didn't know this. btw, this is for mobile safari, so not sure if these optimizations apply - Crashalot 2012-04-05 00:12
@Crashalot I ran that on Safari 5.1 on iOS 5.1: inside is still faster - binarious 2012-04-05 00:16
It'd also be a trivial optimisation to completely do away with i in sample I --- it could just pass it directly to the $(...).append cal - tobyodavies 2012-04-05 00:17
I understand that inside in this case is faster because of scoping, but what about a normal loop like: for (i = 0; i < 10; i++) var tmp = $(something). Here it seems declaring the tmp-variable once, outside the loop, would be faster - powerbuoy 2012-04-05 00:23
@powerbuoy - JS doesn't have block scope: a var statement inside a for loop is treated as if it was at the top of the current function scope (though the actual assignment happens at the line you put it) - nnnnnn 2012-04-05 00:29
Ah yes I know it's available outside the for loop in that case, my question was more on performance. Edit: because when I saw the title of the OP's question I thought that was what he meant - powerbuoy 2012-04-05 00:52
If anything, these tests show that jsperf cannot be trusted at all. The results should be equal because the work actually done in the tests completely shadow nano optimizations such as variable declarations. -1 for you and everyone thinking this prooves anythin - Esailija 2012-04-05 13:37
I hope you read the part "But the difference is not worth enough to care about. - binarious 2012-04-06 11:40


3

This is a micro optimization, stop doing that.

Instead invest energy into writing readable code and doing documentation and testing for the code.

However, there are some high level issues that are worth optimizing for:

  • Removing bloated abstractions like jQuery that make you an order of magnitude slower.
  • Reducing the amount of rendering and drawing you're doing on screen
  • Reducing the big O complexity of your algorithms
  • Reducing the latency of server-client trips.
2012-04-05 00:24
by Raynos
what do you recommend for mobile safari if not jquery - Crashalot 2012-04-05 00:35
Mobile is a resource constrained environment. Performance matters in some apps. You don't have enough information to suggest this is not needed - AutoSponge 2012-04-05 00:36
@Crashalot you don't need libraries, you use "vanilla javascript - Raynos 2012-04-05 00:54
@Downvote Y U hatin - Raynos 2012-04-05 00:57
I didn't (and don't) downvote, but the expression "Y U hating" made me want to.. - nnnnnn 2012-04-05 04:54
-1 for suggesting focussing on readable code and suggesting replacing jQuery with vanilla JS in the same threa - tobyodavies 2012-04-05 04:54
@tobyodavies If you need jQuery to write readable code then you need to learn to write readable cod - Raynos 2012-04-05 05:06
@Raynos if anyone can write cross-browser JS without dozens of feature/browser detection tests and/or re-implementing most of jQuery that is clearer than the same features implemented with jQuery I'd be impressed. Browser compatibility is a big part of what makes vanilla JS ugly, that and the ugliness of DOM interfaces. It's easy to write vanilla JS that reads how you are doing something, it's much more difficult to make it read as a description of the result you get. jQuery does the latter reasonably well IMO - tobyodavies 2012-04-05 05:17
cross browser JS is a trivial thing, supporting legacy browsers is non-trivial. jQuery is an ugly library, I personally prefer the DOM interfaces. There are projects like the DOM-shim that are a far cleaner way to handle legacy browsers. I find well written code readable, jQuery and any code written using it is not. Any code written using vanilla JS and sensible functions is - Raynos 2012-04-05 13:10


0

That would depend on implementation, but in principle I don't think there will be any noticeable difference in performance. Since you're using jQuery to loop, the i variable will be in the function scope in the first case, and in the outer scope in the second case. That might have a slightly different effect on memory allocation, but I doubt it would be noticeable. The only way to be sure it choosing an implementation and trying to measure the performance in it.

2012-04-04 23:58
by mgibsonbr


0

These are potentially semantically different so this is an apples to oranges comparison: e.g. if you were using i inside ajax callbacks instead of synchronously you would almost certainly be using the last assignment to i several times, rather than each of the different values if you made this change.

pure speculation follows:

Consequently we know that if you were using the full potential of the var inside form you would need different memory addresses for each i, then it must be doing more work.

It would take significant analysis to determine that $.each uses it's callback argument synchronously. Consequently, if this is a valid optimisation, I suspect most JS compilers will not be able to make it, and making it by hand should give you (constant time) speed and memory improvements.

Other considerations:

More lexical scopes potentially mean linearly increasing cost of looking up a variable.

2012-04-05 00:07
by tobyodavies
Ads