art with code

2009-11-16

Further optimizing a small JavaScript loop

Continuing from Optimizing a small JavaScript loop, there were some suggestions in the comments on how it might be made faster (or cleaner.) I tested them all just now, along with a couple ideas of my own.

Using var l = imgs.length; while (l--) instead of a for-loop


No measurable effect on the speed of my loop, except that I had to reverse a sort order to account for the reverse traversal. And I don't like reversing sort orders, it's hard enough to keep these things straight when you're not counting backwards.

Not copying function args to local vars


I.e. instead of the redundant var ctop = arg2, use arg2 directly. Made the code cleaner. Didn't have any measurable effect on runtime.

Using object properties directly instead of copying them to local vars


I.e. instead of var etop = e.cachedTop use e.cachedTop directly. Made the code cleaner, no effect on runtime.

Using imgs[i] everywhere instead of var e = imgs[i]


That seems slower to me. And more typing. But, no measurable effect on runtime.

Using a > b ? a : b instead of Math.max(a,b), ditto for Math.min


This was one of my ideas. No measurable effect on runtime.

Inlining isVisible to the loop


Again, one of my ideas. Again, no measurable effect on runtime. Maybe a 5-10% improvement, but my measurement error is 10-20% :|

Moving setting e.trans outside the loop


Sounds like a good idea. Need to refactor my code to do that.

Conclusions


Most of the things people tell you will improve JavaScript performance actually don't. Measure.

Also, I need a better way to measure runtimes. What I have now is a keydown handler that runs the loop a hundred times and prints the elapsed time to Firebug console. The amusing thing is that the exact same code can give 100-run runtimes ranging from 550 ms to 720 ms. And my system load is zero.

I suppose the problem is that this benchmark is run as part of my existing application. So, if any enterprising soul wants to have a go, make the bit you benchmark a separate page.

3 comments:

Lon said...

Are you also measuring impact on memory?

Justin Johnson said...

"Using var l = imgs.length; while (l--) instead of a for-loop" -- I am never happy to see this optimization. It's not always applicable to run the loop backward and rarely improves anything.

"Not copying function args to local vars" doesn't have an effect in this case because you are not modifying them afterward. JavaScript uses copy-on-write, so those local vars are just references. If you were to alter them within the function, then you may have seen a hit to performance, but probably not much considering they are just int's, and not large data structures.

"Using object properties directly instead of copying them to local vars" -- This is theoretically slower since 1) JavaScript uses copy-on-write (as discussed above), and 2) involves not one, but two lookups: the first being the object (e), and then its property.

"Using a > b ? a : b instead of Math.max(a,b), ditto for Math.min" Although it was worth a shot, the JavaScript library is highly optimized, even for simple things like this.

My suggestion would be to define the regexp outside of the loop, although the interpreter may be optimizing thins already.

Also, it seems that these images may have some sort of vertical relation to each other. If the images are a fixed distance vertically from each other and are a fixed size, you only need to access `e.offsetTop` and `e.offsetHeight` for the first image, and the rest can be calculated from that point based on `i`.

Good post and good man for measuring.

Anonymous said...

JSLitmus is a pretty great way to test this sort of thing. Makes Google chart URLs to post on your blog too :)

http://www.broofa.com/Tools/JSLitmus/

Blog Archive