When JavaScript was first invented, I don’t think anybody imagined just what we would be doing with it today. In fact, a lot of people today might not realize how much it’s being used behind the scenes of all the modern Web 2.0 applications.
Right now, JavaScript is virtually the only language that can be used in a client-side browser-based application. Sure, there’s always VBScript if you want to limit which browsers can run your application. And there are many other languages if you want to require visitors of your Web site to download an add-on to provide support for that language. But if you want to write an application for the most browsers with the least amount of headache for your users, you’re pretty much stuck with JavaScript on the client end. (The server end is wide open in terms of language and platform choices, of course.)
Originally, JavaScript was just used to add fancy little animations (like graphics falling down the screen like rain) and other such annoyances to Web pages. But today JavaScript is being used for serious work. For example, on Facebook you can send an e-mail message within a single DIV element that opens up, allowing you to type in the message, send it and update the thread of messages on the page, all without leaving the page. And that’s all done through JavaScript.
But the problem Web developers are hitting is that JavaScript is a slow, interpreted language. While today’s computers are able to move along pretty quickly and the sites do function reasonably well, we are nevertheless limited as to how our sites can perform. And soon we’re going to hit a brick wall if something isn’t done to help make JavaScript run better.
There are several solutions to this problem. One approach that has worked well with scripting languages in the past is JIT (Just-in-Time) compilation. Here, code is compiled to native machine code as needed. This approach only works well with routines that are called over and over. If you’re calling a routine just once-one that doesn’t have many for loops-it’s often faster to just interpret it rather than first compile it and then run it. The compilation can take longer than just running the interpreted form. But if you have a routine that’s called over and over, compiling it the first time and then running the compiled form can make a big difference.
Language developers have taken the JIT concept and mixed it with other concepts such as various types of optimization to significantly speed up languages. The newest Firefox version that is still in development, for example, includes a JIT and optimization compiler for JavaScript, allowing it to run much more quickly. That is certainly good news. (And, interestingly, the original designer of JavaScript, Brendan Eich, is the CTO of Mozilla, which makes Firefox. So, needless to say, I suspect we will see some serious advances from Firefox in the JavaScript world.)
Google, however, has taken a slightly different approach to making JavaScript run faster. Google does indeed compile it, but the approach is different from a typical JIT solution. Let’s see what Google is doing.
The Problem with Compiling JavaScript
The Problem with Compiling JavaScript and Other Dynamic Languages
If you’ve programmed in C++, you’re well aware that before you can access a class, you need to have the class fully defined. Typically you’ll put your class definition in a header file. This definition includes the word “class,” the name of the class, and a list of all the member variables and member functions. Later in your code you can create objects that are instances of the class.
The class is much like a cookie cutter for objects. Once the program is running and you create an object, the object has the members it will have until it is destroyed. You can change the value of the members (such as changing the height member of a Rectangle object from 10 to 20 or changing the balance member of the CheckingAccount object from 100 to 100,000,000) but you can’t add or remove members. While your program is running, you can’t add a depth member to your Rectangle class. The only way you can make changes is by changing the code and recompiling. But then when you run the program, all your Rectangle objects will have the new member.
JavaScript, however, is a dynamic language, and the whole concept of classes changes drastically. You can add and remove members of an object while the program is running. Thus, you can have two Rectangle objects, for example, and then add a depth member to just one of those objects.
In fact, although it’s not necessarily the best programming practice, you can even provide the user of your program with a text box where he or she can type in a name, and then you can add a member to an object by that name. Thus, your user could suggest the name eWEEK for a member, and you could add that member to the object and give it a value.
And further, that value can be any type you want-again something totally different from C++. In C++, if you have a Rectangle class with members Height and Width and you specify that they are to hold integers, then you can’t store a string in one of these members while the program is running. In fact, the compiler will catch it and stop you while you’re compiling before you’re even able to run the program.
But not so with JavaScript: You can store the number 10 in your eWEEK member, or you can store the string “Awesome Publication” in the member.
As you can probably imagine, this makes for some serious problems with compilation. Microsoft, for example, hit these snags when trying to add dynamic languages to the list of languages that can be compiled under the .NET run-time. Microsoft’s CLR (Common Language Runtime) is strongly typed and not dynamic, making languages such as JavaScript and Python difficult to compile. Microsoft now has support (primarily in its Silverlight product) for dynamic languages, but to do so it had to add an entire dynamic language layer on top of the run-time.
(And incidentally, just to make life even more interesting, almost anything in JavaScript can be treated as an object and have members assigned to it at run-time, including even functions.)
Google has taken a unique approach to compiling JavaScript. It’s implemented something known as hidden classes.
Googles Solution: Hidden Classes
Hidden Classes in V8
Google drew on its team members’ expertise with earlier compiled, dynamic languages, such as an experimental language called Self (created when the team members worked at Sun Microsystems). To a programmer like myself, the concept at first sounds horrible. When I first read about it I was shocked that they would do something so seemingly inefficient. But in fact, it works beautifully.
Here’s how it works. In JavaScript, objects are initially created with no members. You could create two new objects and neither will have any members. Then your code can add members. You might have a line of code that creates an object; then the next line adds on a new member called Width; then the next line adds a member called Height.
During this time, your object went through three stages: First it had no members, then it had only one member, then it had two members.
Now, typically such member-adding code will take place in a constructor function. This is a special named function in JavaScript that runs when you create a new object. The function gets a name, and that name is in turn used for the class of the object. Thus, you might have a function called Rectangle. Its code will have a line to add a Width member, and then a line to add a Height member. And this is where the V8 smarts of Google Chrome come in.
While compiling the code, V8 will create in the background a compiled class (just like you have in C++ at run-time) that contains no members. Then as the compiler discovers the line of code that adds a Width member, the compiler will create a second class, this one with the Width member. Then as the compiler encounters the next line, it will create a third class, this one with the Width and Height members.
That’s right, it creates three classes. But the compiler is smart, because later on in your code, when you create several instances of your Rectangle class, the compiler will know to use the third class.
Of course, that’s sort of a simple example. In fact, you might add the eWEEK member to one of your objects outside of the constructor. In that case, the compiler will create a fourth class, this one including the eWEEK member.
In other words, you might have multiple instances of Rectangle, and behind the scenes several of them may share the third class, while others might have their own separate class. These are called hidden classes.
And, of course, the rest of your code is compiled to machine code; the compiler doesn’t just make a bunch of classes. That’s where the efficiency actually comes in. The idea of generating all these classes is only a minor tradeoff in the long run, because ultimately your code is running as native machine code and is far, far faster than traditional, interpreted JavaScript.
Taking Out the Garbage
Collecting the Garbage
One of the huge problems with languages like JavaScript is garbage collection. Garbage collection just refers to the problem of using memory and being done with the memory but the computer not being able to reuse the memory because it doesn’t know if you still need it. Got that?
If not, here’s how it works: Suppose I create a Rectangle object. I use that in a calculation. Then I’m done with the object. In a language like C++, you write a line of code that tells the run-time library that you’re done with the object. The run-time library will then delete the object and allow the part of memory where the object was stored to be used again for other objects.
But in languages like JavaScript, you don’t explicitly tell the run-time you’re done with the object. The run-time does, however, have ways of figuring out that you’re done with the object. Typically, if a function creates an object, when the function is finished the object can be cleaned up too. But not always: The function might pass the object on to three more functions to use, for example, and only after the run-time system figures out that all four functions-the original and the three others-are finished can it figure out that the object isn’t needed anymore and free the memory.
But the problem is the object might get saved away as a member within yet another object. Then the run-time can’t delete the first object until this other object is no longer needed! Can you say, big mess? Yes, there is more than one reason it’s called “garbage collection,” and I’m sure some people would like to include other choice words instead of garbage, as well as directives about other people cleaning up their own, uh, messes.
Garbage collection is always a problem with languages, because often the actual garbage collector (the code that does the cleaning) only runs occasionally, and when it does, the program slows waaaaaaay down.
Google describes in its developer documentation a sophisticated garbage collector that Chrome uses. This collector stops everything and does its job very quickly while only collecting what’s necessary, and then allowing everything else to resume. Personally, that sounds suspicious to me; however, I can understand how that could be better than having the garbage collector slowly churn away for minutes on end while you’re continuing to do your work, albeit slowly, due to the garbage collector slowing everything down-and, with the work you’re doing slowing the garbage collector down, causing it to run even longer. So perhaps this new method is better.
Conclusion
Conclusion
I have a couple of Web sites I use regularly, including one for checking my personal e-mail via a Web interface. This particular interface is really nice, but it’s always been horribly slow. For that reason, I only use it when necessary.
I tried it using Chrome and was impressed. The first time the Compose box opened, it was a little sluggish as all those formatting buttons slowly drew. But the next time I ran it, it opened instantly, and definitely felt like I was using a desktop (in other words, non-Web) application. Now this, of course, is just anecdotal and not a benchmark test. But it was fast.
But is Chrome’s V8 faster than the latest development build of Firefox? And is it faster than anything Microsoft might secretly be doing? (I’m bettin’ that Microsoft is working on its own native compilers, although I don’t know for sure.)
So far, the jury is out. I’ve seen pages “proving” through benchmarks that V8 is faster than Firefox’s new engine. But I’ve also seen pages “proving” that Firefox’s engine is faster. It’s hard to say. One thing is for sure: They’re both fast, and they both fly. And that’s great news for us developers, and even better news for the users across the planet fighting with these slow Web 2.0 applications.
Jeff Cogswell is the author of Designing Highly Useable Software. Currently Jeff is a senior editor with Ziff Davis Enterprise. Prior to joining Ziff, he spent about 15 years as a software engineer, working on Windows and Unix systems, mastering C++, PHP, and ASP.NET development. He has written over a dozen books.