Google recently released a new feature for their Google Docs writing application; the ability to draw a vector graphic and insert it in your document. This drawing module uses SVG and VML, much like DojoX GFX. I was curious about their code and explored with Firebug. To my surprise, I found that most of their code uses variables in the global scope. The code is compressed, but when observing with Firebug’s DOM tab, there are several pages and a few hundred lines of global variables.

DocFirebug

This surprised me. I had always read that working in the global scope was slower than working in a new object and that when building web applications and looking for maximum performance, you should avoid window.myVar and opt for myObject.myVar. Technically these terms would be a variable for a value set at the window level, and a property for a value set at the object level. For the purposes of this test, I’ll be referring to them as globals and locals.

So the basic idea is to conduct a test where I get and set variables in the global and local scope and time them.

The Test Code

First I made variables to be used in the global and local objects. They were designed to be very random, to offset any possibility of sequential look-ups. I ended up using 25,000 variables, because it was enough to give a decent comparison range, and not enough that it would cause memory errors in Internet Explorer 8. This step takes time obviously, but since this would be more about loop and Array performance, it is not relevant and not included in the test times.

v = [];
makeVars = function(amt){
	for(var i=0;i

The next step is to set the locals in a fresh object, and set the globals in the window. All variables are set to a simple boolean of true:

obj = {};
setLocals = function(){
	for(var i=0;i

Next is the code to access the variables:

getGlobals = function(){
	for(var i=0;i

Now we can execute our functions wrapped in timers. I'm using a custom-written timer, since we will be testing in browsers that are not equipped with Firebug:

timer.start("l");
setLocals();
var lSet = timer.end("l");

timer.start("g");
setGlobals();
var gSet = timer.end("g");

timer.start("gl");
getLocals();
var lGet = timer.end("gl");

timer.start("gg");
getGlobals();
var gGet = timer.end("gg");

The custom-written code actually has a lot to it, including logging, averaging, and storing results, but I'm not going into that here.

I then ran this test ten times and took averages of each for all the major browsers. The results:

[TABLE=5]

For a change, we are not comparing the browsers to each other. We know Internet Explorer is slow (although surprisingly, it beats Firefox in the globals test), and we know that Safari 4.0 is going to be an insane aberration of web technology what we expect.

Focusing on Firefox 3.5 in the first column, we see that everything we've read is true. Setting the globals takes 285 milliseconds, while setting the locals takes 24 milliseconds. Setting locals in Firefox is ten times faster than globals, and getting locals is over eight times faster.

What's interesting, even though browser comparisons are not the point, is that Firefox is slower than all other browsers except Internet Explorer 6 – and Firefox 3.5 is even slower than Firefox 3.0 for this test. This is possibly because I haven't optimized for Tracemonkey, but Firefox does not perform as well as expected. Regardless, the test is consistent with the expected results: globals are slower than locals in all browsers. Except for Safari, where the difference is insignificant.

Analysis

The following are charts for Firefox and Internet Explorer. There is an additional bit of data called Complex Object. Here I create an object within an object within an object 25,000 times. This was the second most challenging thing for Firefox and the most challenging thing for Internet Explorer.

IE Chart

You'll notice the spike in Firefox at around 19,000 objects. This test was run ten times and averaged, so I assume this is where the Garbage Collector (GC) kicks in:

Firefox Chart

Why Firefox 3.5 is slower than version 3 and slower than Internet Explorer is not immediately clear. One answer may be in XPCOM, the development framework that Mozilla uses which is similar to Microsoft's COM. Scott Collins, one of the original software engineers at Mozilla and Netscape was largely responsible for the authoring and implementation of XPCOM and laments the fact that while it's a good framework, it was overly utilized and a cause for poor memory management and code bloat. In fact, Mozilla looks to be moving away from XPCOM as of Firefox 4.0

So in theory, the window space should run faster because there are fewer scope and prototype chains to climb. But this entirely depends upon the browser implementation. The window object is more than just JavaScript, it's also the interface to the browser engine.

Notes

I've been burned by Firebug before, so I uninstalled it and reran the test. The results were unchanged.

I also tried running the test ten times in a row within the same page to see if this would allow Tracemonkey to identify and compile the test as "hot code". It had no effect.

Conclusion

Small web pages with several global functions and variables would not experience a noticeable affect. Web applications would probably not have a noticeable impact neither, but since the results are indisputable that the global space is slower, its curious that the performance conscious Google chose to deliver this code. The results are not staggering enough to cause anyone to change their coding habits, but they show a good argument for form following function. Working in local objects is not only a good idea for code organization and maintenance, it will perform better too.

Another lesson to be learned is that even in Safari, setting variables always takes longer than getting them. This may be obvious computationally, in that there are extra cycles involved in creating that variable and finding a memory location for it. But it's something to keep in mind while writing our web applications. Writing always takes longer than reading.

Teaser

I made an unexpected discovery while conducting the tests. In my next post, I'll show more data in regard to page unload performance.