0

I have been writing a JS algorithm. Its blazing fast in chrome and dog slow in FF. In the chrome profiler, I spend <10% in a method, in FF the same method is 30% of the execution time. Are there javascript constructs to avoid because they are really slow in one browser or another?

One thing I have noticed is that things like simple variable declaration can be expensive if you do it enough. I sped up my algorithm noticable by not doing things like

var x = y.x;
dosomthing(x);

and just doing

dosomething(y.x)

for example.

3
  • Variables are cheap. Assignment is also cheap as it only copies primitive values, or references in case of objects. I don't think it can be a performance bottleneck. Commented Oct 3, 2010 at 16:57
  • @galambalazs when doing something hundreds of thousands of times, i guess every assignment matters? Commented Oct 3, 2010 at 21:33
  • definitely check out this proposal. It's almost there, just needs a little more support :) Commented Jan 17, 2011 at 22:08

3 Answers 3

5

As you've found, different things are issues in different implementations. In my experience, barring doing really stupid things, there's not much point worrying about optimizing your JavaScript code to be fast until/unless you run into a specific performance problem when testing on your target browsers. Such simple things as the usual "count down to zero" optimization (for (i = length - 1; i >= 0; --i) instead of for (i = 0; i < length; ++i)) aren't even reliable across implementations. So I tend to stick to writing code that's fairly clear (because I want to be nice to whoever has to maintain it, which is frequently me), and then worry about optimization if and when.

That said, looking through the Google article that tszming linked to in his/her answer reminded me that there are some performance things that I tend to keep in mind when writing code originally. Here's a list (some from that article, some not):

  1. When you're building up a long string out of lots of fragments, surprisingly you usually get better performance if you build up an array of the fragments and then use the Array#join method to create the final string. I do this a lot if I'm building a large HTML snippet that I'll be adding to a page.

  2. The Crockford private instance variable pattern, though cool and powerful, is expensive. I tend to avoid it.

  3. with is expensive and easily misunderstood. Avoid it.

  4. Memory leaks are, of course, expensive eventually. It's fairly easy to create them on browsers when you're interacting with DOM elements. See the article for more detail, but basically, hook up event handlers using a good library like jQuery, Prototype, Closure, etc. (because that's a particularly prone area and the libraries help out), and avoid storing DOM element references on other DOM elements (directly or indirectly) via expando properties.

  5. If you're building up a significant dynamic display of content in a browser, innerHTML is a LOT faster in most cases than using DOM methods (createElement and appendChild). This is because parsing HTML into their internal structures efficiently is what browsers do, and they do it really fast, using optimized, compiled code writing directly to their internal data structures. In contrast, if you're building a significant tree using the DOM methods, you're using an interpreted (usually) language talking to an abstraction that the browser than has to translate to match its internal structures. I did a few experiments a while back, and the difference was about an order of magnitude (in favor of innerHTML). And of course, if you're building up a big string to assign to innerHTML, see the tip above — best to build up fragments in an array and then use join.

  6. Cache the results of known-slow operations, but don't overdo it, and only keep things as long as you need them. Keep in mind the cost of retaining a reference vs. the cost of looking it up again.

  7. I've repeatedly heard people say that accessing vars from a containing scope (globals would be the ultimate example of this, of course, but you can do it with closures in other scopes) is slower than accessing local ones, and certainly that would make sense in a purely interpreted, non-optimized implementation because of the way the scope chain is defined. But I've never actually seen it proved to be a sigificant difference in practice. (Link to simple quick-and-dirty test) Actual globals are special because they're properties of the window object, which is a host object and so a bit different than the anonymous objects used for other levels of scope. But I expect you already avoid globals anyway.

Here's an example of #6. I actually saw this in a question related to Prototype a few weeks back:

for (i = 0; i < $$('.foo').length; ++i) {
    if ($$('.foo')[i].hasClass("bar")) { // I forget what this actually was
        $$('.foo')[i].setStyle({/* ... */});
    }
}

In Prototype, $$ does an expensive thing: It searches through the DOM tree looking for matching elements (in this case, elements with the class "foo"). The code above is searching the DOM three times on each loop: First to check whether the index is in bounds, then when checking whether the element has the class "bar", and then when setting the style.

That's just crazy, and it'll be crazy regardless of what browser it's running on. You clearly want to cache that lookup briefly:

list = $$('.foo');
for (i = 0; i < list.length; ++i) {
    if (list[i].hasClass("bar")) { // I forget what this actually was
        list[i].setStyle({/* ... */});
    }
}

...but taking it further (such as working backward to zero) is pointless, it may be faster on one browser and slower on another.

Sign up to request clarification or add additional context in comments.

2 Comments

Related to the 'count down to 0', I recently saw another variation, which I thought was clever (if a bit confusing): for (var i = arr.length; i--; )
@Ryan: :-) Yeah, I've seen that one (and its cousin, var i = arr.length; while (i--)...).
1

Here you go:

http://code.google.com/intl/zh-TW/speed/articles/optimizing-javascript.html

2 Comments

Please don't do link-only answers: meta.stackexchange.com/questions/8231/…
Another reason is that a link may be broken after a while.
1

I don't think this is really a performance thing, but something to avoid for sure unless you really know what's happening is:

var a = something.getArrayOfWhatever();
for (var element in a) {
  // aaaa! no!!  please don't do this!!!
}

In other words, using the for ... in construct on arrays should be avoided. Even when iterating through object properties it's tricky.

Also, my favorite thing to avoid is to avoid omission of var when declaring local variables!

1 Comment

...or indeed global variables!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.