Optimizing JavaScript for the V8 Engine

Originally Published On AppFog

August 4, 2013

Share +

For those of you like myself that didn’t have the good fortune of going to Google I/O, I hope you caught this video, “Breaking the JavaScript Speed Barrier:”

As an aspiring developer, this was far and away the most intriguing and helpful video from the conference. This talk, delivered by Google’s Daniel Clifford, provides a number of essential guidelines for writing JavaScript that is better optimized for running on Google Chrome’s V8 JavaScript Engine. Google has been doing pretty incredible things in the last few years with JavaScript, improving benchmarks and narrowing the speed gap between JavaScript and other languages that was once thought to be unbridgeable.

We should be grateful that Google has invested so much time and energy into optimizing JavaScript performance. It has never been more important as a language, and its star is unlikely to fade anytime soon. For Clifford, optimizing JavaScript performance not only helps us do the same old things faster and better. It also broadens our development horizons and transforms the kinds of things that are possible, especially in the sphere of front-end development.

I won’t give a fully fleshed-out summary of the talk, as I would recommend watching it on your own. It’s briskly presented and quite conversational. But I will lay out some of the bits that struck me as the most essential take-home points.

Be aware of hidden classes. Hidden classes constitute one of the crucial architectural elements of the V8. JavaScript has no explicit type system (as in Java and other languages). While this is often pragmatically useful, according to Clifford it can be costly at compile time because any JavaScript interpreter has to figure out what data type is being used.

Constructing a class is somewhat expensive in terms of time to begin with, but it gets much cheaper after that. Unless you going around adding properties to the hidden class, which will slow things down a great deal. Here’s how not to do things (culled and modified from this site):

Notice that we’ve added a property to the class “point” in the last line. Although we have only one explicitly defined class in play here, V8 sees the new property and expands the number of hidden classes to two. Clifford would likely recommend doing the following instead:

This will run much more quickly than the above example. We declare a class, constructing an object in accordance with that class, and get the heck out. The number of hidden classes in play remains at one. We should be exercising this kind of vigilance all the time. Which brings me to a related piece of advice:

Monomorphic > polymorphic. There may be situations in which changing class properties dynamically turns out to be necessary, but this should be avoided at all costs if possible. The first example I used above is an example of polymorphic coding, in that we’re using multiple hidden classes, probably without even realizing it (unless we already know what’s going on under the hood in Chrome). Conversely, coding as monomorphically as possible means coding parsimoniously and in a way that is attuned to the V8.

Careful with your arrays. First of all, how you deal with arrays depends upon their size. If you are dealing with arrays under 65,000 members (Clifford labels these small (!) arrays), you should pre-specify the size of the array, so that the V8 knows how much memory to allocate. And so this:

The difference here is subtle, but the larger the array you’re working with, the more optimization gains are available. Interestingly, if you’re dealing with “large” arrays (with more than about 65,000 members), it’s actually better to start with an empty array with an unspecified number of members and then build as you go.

Another important piece of advice regarding arrays is related to Clifford’s advice about hidden classes. It’s always better to maintain type consistency across arrays (if possible) instead of mixing and matching data types, as in the array [5, “aardvark”, true, 6.71].

Identify the real problem. You should always try to make sure that the problem is really a JavaScript problem and does not reside elsewhere. Because JavaScript is usually tied to the DOM, it is often the case that the problem resides in the JavaScript-DOM relationship and in the general slowness of the DOM rather than in the JavaScript itself. If you’re running benchmarks, try and do so on “pure” JavaScript. This strikes me as a solid piece of more general advice extending beyond V8-oriented optimization.

The Chrome team is still very hard at work on these problems, and the V8 is still very much a work in progress. Clifford admits that there are certain elements of the language that have not yet been optimized, for example try/catch blocks, which Clifford suggests embedding in declared functions rather than letting them dangle on their own.

Following these tips (and others not mentioned here) enabled Clifford to take his non-optimized JavaScript code for calculating the 25,000th prime number from hundreds of times slower than C++ to only 17% slower. As with any and all language benchmarks, take this with a grain of salt: Clifford freely admits that the example was chosen because he knew that it would do well in the V8 engine. But even with the grain of salt dutifully swallowed alongside the presentation, Clifford’s case for the V8 is nonetheless very convincing. I would love to see more side-by-side tests run using less cherry-picked examples.

If I were to venture a few expectations about the V8 project, they would be the following:

Over time, more and more elements of the language will be grist for the V8 mill. There is room for improvement, and Google is on the case. The future progress of the V8 engine will likely coincide directly with the rise to dominance of Chrome itself.

In a race to keep up, we can most likely expect the other major browsers (IE, Firefox, et al) to embark on their own JavaScript optimization journeys. We’ll have to wait and see if optimizing JavaScript leads to a set of cross-browser best practices, or if the optimization methods in each will diverge in ways that impacts how we optimally code.

This is just a set of first impressions and thoughts. There is much, much more to be learned from the video, and I strongly suggest sitting down and more fully digesting it on your own.