Skip to content

Instantly share code, notes, and snippets.

@davemo davemo/gist:3093034 forked from rmurphey/gist:3086328
Created Jul 11, 2012

What would you like to do?
What's wrong with Netmag's "Optimize your JavaScript" post

What's wrong with Netmag's "Optimize your JavaScript" post

Update: The original post on Netmag has been updated since this was written.

This is a response to an article posted on Net Magazine earlier this week that offers optimization tips for those writing JavaScript. Generally, these performance-related articles are inaccurate and harmful to new Front-End Developers trying to understand the craft -- there are many other things you should do to improve a page's performance before worrying about the purported perf hit of multiplication vs. division -- while the intention of this post may have been to inform and educate it did the opposite: it offered inaccurate advice.

A few of us have taken the time to assemble a list of corrections in the hope that Net Magazine will update the article and avoid leading Front-End developers astray.

Things that are incorrect

  • Calling array.push() five times in a row will never be a "performance improvement." The article confuses creating an array literal ["foo", "bar", "baz"] and then using .join("") on it vs. creating an array, pushing individual items, and then joining. See here for the proof, and see here for a possible explanation.

  • The article sets up a for loop as follows: for(var i = 0; length = 999; i <= length; i++){. This results in a syntax error.

  • The article suggests for(var i = my_array.length; i--) as a shorter version of a for loop. While you can get by with using the decrement as the conditional, omitting the semi-colon at the end causes a syntax error. Also, if someone were to move the semi colon to before the decrement, it would cause an infinite loop. In our opinion, if you were to do this style of cleverness, a while loop is much more sane: var i = my_array.length; while( i-- ) {}.

  • Because JavaScript lacks block scope, variables declared inside blocks are not local to any block. The variable declaration is actually "hoisted" to the beginning of the nearest execution context (function body or global scope) such that var foo; for(...) { foo = 1; } behaves exactly the same as for(...) { var foo = 1; }. It is, however, considered bad practice to declare variables inside of blocks, because novice JavaScript developers infer from it that JavaScript has block scope.

  • Creating a variable to hold the length property in a for loop is typically no faster (and sometimes slower) in Chrome. Making it faster in Firefox doesn't make it magically "faster" everywhere.

Things that can be improved

  • The article mentions DOM performance almost as an afterthought. When it comes to performance, rarely is JavaScript the problem -- DOM reflows are a much more likely culprit for performance issues, but even just modifying elements via the DOM API in memory is still slow. This is one of many reasons people use client-side templates, which the article does not mention. All of that said, if you're looking for real performance gains, take a long, hard look at your HTTP overhead. Chances are that optimizing an image or two will make more difference than any improvements you can make to your JavaScript.

  • The article references avoiding unnecessary method calls within conditionals, and then demonstrates by accessing a property, rather than calling a method.

  • The article references local vs global variables, and then proceeds to demonstrate the concept with an instance property, not a local variable.

  • The article references the global Array constructor function to create a new array, rather than using the Array literal [] syntax which is, itself, known to be a performance improvement.

  • The section "Calling methods or properties on array elements" is true, but somewhat misses the point: lookups of any sort should be stored in a variable, rather than being repeated. This guidance has nothing to do with array elements; it's just as true for the result of a function call.

  • In "encapsulating methods within class declarations" example, the article fails to point out that there are really 2 performance metrics to be tested: 1) cost while creating a new instance object and 2) cost while dereferencing a method from an instance object. The provided example only discusses #1 without addressing #2. What's interesting is that, typically, #1 and #2 are mutually exclusive. When methods are defined directly on an instance object, they consume more memory and cycles (because a new function object must be created for each instance object). When methods are defined on the prototype however, they must only be defined once, so the initial overhead is less, but each time the method is dereferenced from the instance object, the cost is slightly higher because the prototype chain must be traversed. A compromise can be had whereby a previously-defined function is defined as a method on each individual instance, thus reducing memory usage, but the cost of initially assigning the method probably won't offset the cost of accessing the method via the prototype down the road.

  • In "encapsulating methods within class declarations" the article does not accurately describe semantic, language level behaviour and use cases for instance properties and methods, and prototype properties and methods. Comparing instance properties and methods with prototype properties and methods is like comparing a knife with a stealth fighter jet -- yes they can both be lethal, but one is far more efficient and suited to larger scale tasks and the other is suited to individual, "case by case" (ie. instance) tasks. Additionally, any time that data properties are defined on a prototype, it's likely a mistake that will result in bugs.

  • In "Unnecessary method calls within conditionals in For Loops" there is a poor example that itself misses the point that should've been made: operations in loops have costs, be mindful of this. In addition to this mistake, there is actually no such thing as a "conditional in For Loops"; the article omits the actual name "Expression", as in... IterationStatement, optional Expression.

  • The article advises using Firebug for profiling code, but provides no guidance on how to do this, or even a link to any guidance. This article offers step-by-step guidance on using the Chrome developer tools to identify performance bottlenecks -- which, as we mentioned, you should only do after you've done a whole lot of other things you can do to improve your page's performance. The YSlow page offers a good list of things to do to improve page performance.

In Summary

When misleading and inaccurate content gets published by a prominent site it can lead to the proliferation of numerous bad practices and anti-patterns. It is our hope that by providing this correction that those interested in JavaScript performance will have alternate resources to peruse and even consider whether they can optimise their web applications in other areas that will yield better returns on time spent.

Want to know more? See some performance tests that debunk some of the things presented in this article :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.