20 Jan 2010

Performance Optimizations Made By Microsoft, Google, and Yahoo JavaScript Minimizers

6 Comments Uncategorized

In my first post about JavaScript compression and the different levels supported by the three major competitors in the JavaScript minimization, obfuscation, and optimization tools space.  I the article I discussed which tool provided the best compression in regards to the resulting byte count.  And found that Google took the over all crown with Microsoft following very closely behind.  A comment posted on that article by Eric J. Smith of Code Smith, provided a nice lead in to my second article in this series, he posted this comment:

Eric J. Smith Comment

So if you haven’t guessed it yet by the title and then by Eric’s comment this post is going to be on the optimizations provided by the tools.  So lets get started…

Setup

Back in October I saw an interesting article on this same subject comparing Yahoo and Microsoft on site called Ajaxian. But at the time Microsoft AJAX Minimizer was only on RC6, and as of this article is at version 1.1, so somethings have changed and I wanted to provide a more relevant comparison which included Google too. I borrowed Ajaxian’s code they used to test the different tools for my own experiment in this article.

function notCalled(text) {
	alert(text);
}
/**
 * @license comment
 */
var o = (function(){
var o = {};
var b = "on";
var c = "on" + b + "mouse";
var d = c + 1000 + "on";
var x = o[d];
/*!
important comment
*/
var i = 1000;
o["on" + "click"] = function(){};
o["on" + "mouse" + "over"] =
o["on" + "mouse" + "out"] =
o["on" + "mouse" + "move"] = o["on" + "click"];
o["on" + "click"] = o["on" + "click"];
if(i)
i++
;
return o
})();

The above code is designed to test many different aspects of optimization.  Including:

  1. Code that is not called from anywhere.
  2. Preservation of Licenses, Copy Rights, and any other important comments.
  3. Frequently used string literal combination.
  4. Understanding of logic, to remove repeated and unnecessary dynamic access.
  5. Number compression.  (changing 1000 to 1e3)
  6. Get rid of the gibberish variables at the beginning of the function that serve no purpose.

Simple Compression

First things first lets just see how each of them handle simple compression, with out any optimizations enabled on each tool.  I did that by running the following:

# Ajax Minifier
ajaxmin.exe test.js -o output.js
 
# YUI Compressor
java -jar yuicompressor-2.4.2.jar --nomunge --preserve-semi --disable-optimizations -o output.js test.js

# Google Closure
java -jar compiler.jar --compilation_level WHITESPACE_ONLY --js test.js

Above produces the following output

// Ajax Minifier
function notCalled(text){alert(text)}var o=function(){var o={},b="on",c="on"+b+"mouse",d=c+1e3+"on",x=o[d],i=1e3;o["onclick"]=function(){};o["onmouseover"]=o["onmouseout"]=o["onmousemove"]=o["onclick"];o["onclick"]=o["onclick"];if(i)i++;return o}()

// YUI Compressor
function notCalled(text){alert(text);}var o=(function(){var o={};var b="on";var c="on"+b+"mouse";var d=c+1000+"on";var x=o[d];
/*
important comment
*/
var i=1000;o["on"+"click"]=function(){};o["on"+"mouse"+"over"]=o["on"+"mouse"+"out"]=o["on"+"mouse"+"move"]=o["on"+"click"];o["on"+"click"]=o["on"+"click"];if(i){i++;}return o;})();

// Google Closure
/*
 comment
*/
function notCalled(text){alert(text)}var o=function(){var o={};var b="on";var c="on"+b+"mouse";var d=c+1E3+"on";var x=o[d];var i=1E3;o["on"+"click"]=function(){};o["on"+"mouse"+"over"]=o["on"+"mouse"+"out"]=o["on"+"mouse"+"move"]=o["on"+"click"];o["on"+"click"]=o["on"+"click"];if(i)i++;return o}();

Some interesting things I noticed about the above code is:

  • Yahoo was the only tool who preserved the “*!” comment block and Google was the only one who preserved the “**” comment block.
  • Google and Microsoft both changed the number 1000 into 1e3. 
  • Microsoft combined the strings together, that were next to each other.
  • Yahoo added some extra parentheses, around the if(i)i++; statement.

Simple Optimization

Next we are going to look at some basic optimizations made by each tool.  I again did that by running the following:

# Ajax Minifier
ajaxmin.exe -h test.js -o output.js
 
# YUI Compressor
java -jar yuicompressor-2.4.2.jar -o output.js test.js

# Google Closure
java -jar compiler.jar --compilation_level SIMPLE_OPTIMIZATIONS --js test.js

Above produces the following output

// Ajax Minifier
function notCalled(a){alert(a)}var o=function(){var a={},c="on",d="on"+c+"mouse",e=d+1e3+"on",f=a[e],b=1e3;a["onclick"]=function(){};a["onmouseover"]=a["onmouseout"]=a["onmousemove"]=a["onclick"];a["onclick"]=a["onclick"];if(b)b++;return a}()

// YUI Compressor
function notCalled(a){alert(a)}var o=(function(){var h={};var e="on";var j="on"+e+"mouse";var g=j+1000+"on";var a=h[g];
/*
important comment
*/
var f=1000;h.onclick=function(){};h.onmouseover=h.onmouseout=h.onmousemove=h.onclick;h.onclick=h.onclick;if(f){f++}return h})();

// Google Closure
/*
 comment
*/
function notCalled(a){alert(a)}var o=function(){var a={},b=1E3;a.onclick=function(){};a.onmouseover=a.onmouseout=a.onmousemove=a.onclick;a.onclick=a.onclick;b&&b++;return a}();

Some interesting things to note about this new code is:

  • Yahoo and Google still keep their respective comment blocks. 
  • Google and Microsoft both still changed the number 1000 into 1e3. 
  • Google and Yahoo show a better understanding of the code by changing the dynamic event hash mappings in to actual bound properties.  Microsoft still  only combines the strings together.
  • All of the tools obfuscated the variable names.
  • Microsoft and Google both combined the three variables at the beginning of the method in to a one statement.
  • Anybody notice the optimization that Google did b&&b++ instead of if(b)b++, this shows a really good understanding of the code.
  • On the other had Yahoo added some extra parentheses, again, around the if(i)i++ statement, but dropped the extra semi-colon.
  • Google was the only one who got rid of the gibberish variables at the beginning of the function that served no purpose.

Best Optimizations

Next we are going to check out the best possible combination of options for each tool to produce the most optimized code.  We will produce this with the following:

# Ajax Minifier
ajaxmin.exe -hc test.js -o output.js
 
# YUI Compressor
java -jar yuicompressor-2.4.2.jar -o output.js test.js

# Google Closure
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js test.js

You may have noticed that we are using the same commands for Yahoo, this is on purpose, because Yahoo really doesn’t have a simple state the compares to the other tools. 

The following output was produced

// Ajax Minifier
function notCalled(a){alert(a)}var o=function(){var d="click",c="mouse",a="on",b={},f=a,g=a+f+c,h=g+1e3+a,i=b[h],e=1e3;b[a+d]=function(){};b[a+c+"over"]=b[a+c+"out"]=b[a+c+"move"]=b[a+d];b[a+d]=b[a+d];if(e)e++;return b}()

// YUI Compressor
function notCalled(a){alert(a)}var o=(function(){var h={};var e="on";var j="on"+e+"mouse";var g=j+1000+"on";var a=h[g];
/*
important comment
*/
var f=1000;h.onclick=function(){};h.onmouseover=h.onmouseout=h.onmousemove=h.onclick;h.onclick=h.onclick;if(f){f++}return h})();

// Google Closure
/*
 comment
*/
(function(){var a={},b=1E3;a.onclick=function(){};a.onmouseover=a.onmouseout=a.onmousemove=a.onclick;a.onclick=a.onclick;b&&b++;return a})();

Some interesting things to note about this code is:

  • Yahoo and Google still keep their respective comment blocks. 
  • Google and Microsoft both still changed the number 1000 into 1e3. 
  • Google and Yahoo still show a better understanding of the code by changing the dynamic event hash mappings in to actual bound properties. 
  • Microsoft combined the “click”, “mouse” and “on” strings in to variables that are concatenated together in the variables and event references.
  • All of the tools still obfuscated the variable names.
  • Microsoft and Google still both combined the three variables at the beginning of the method in to a one statement.
  • Google still kept the b&&b++ instead of if(b)b++.
  • Yahoo added some extra parentheses, again, around the if(i)i++ statement, but dropped the extra semi-colon.
  • Google still was the only one who got rid of the gibberish variables at the beginning of the function that served no purpose.
  • Google removed the notCalled function, since it was not being used in this script file.  This is good and bad, because if you referenced this from the outside, then this will cause problems when you try to use it.

Final Word

Even though Google ADVANCED_OPTIMIZATIONS scored the highest and Microsoft with –hc turned on scored second on my last post.  I think Google with SIMPLE_OPTIMIZATIONS turned on is my current favorite for providing a good balance between optimization, compression, and compatibility with the original version.  Closely followed by Yahoo with out any configuration options turned off.  These two placed #3 and #5, respectively, in my previous post.

Even though Google with ADVANCED_OPTIMIZATIONS, did the best overall, it still scares me a little for the following reasons that I mentioned last time:

There are a couple things that should be noted about Google Closure with Advanced Options, which may not make the most beneficial option for you to choose when you are trying to minify your files.

  1. Removal of Code You Want to Keep
  2. Inconsistent Property Names
  3. Compiling Two Portions of Code Separately
  4. Broken References between Compiled and Uncompiled Code

Here are the files that resulted from the above testing:

  1. test.js
  2. microsoft.js
  3. microsoft-h.js
  4. microsoft-hc.js
  5. yahoo-all.js
  6. yahoo.js
  7. google-w.js
  8. google-s.js
  9. google-a.js

So which of the following optimizations do you feel the most comfortable with?

Tags: , , , , , , , ,
written by
Nick Berardi
subscribe
If you found this post valuable and would like to see more like it you can follow me.

6 Responses to “Performance Optimizations Made By Microsoft, Google, and Yahoo JavaScript Minimizers”

  1. Reply DotNetWise says:

    Where is the performance discussed here?

    I did expect to read about how the code performs after it was minified.

    All the tricks the yahoo/google/microsoft use come with a cost.
    The question is whether to use them or not.

    For example obj["property"] has same performance as obj.property
    but var p=”property”; obj[p] is a lot worse.

    So I just assume your blog title is wrong as you are not comparing the actual performance of the output code.

  2. Reply Nick Berardi says:

    @DotNetWise Prove your statement? Else we can just assume that what you are saying is bunk. Because how would creating a string as a variable be worse than including the string inline for the obj? It would seem that it would have to do more with the optimizations of the JavaScript engine that runs the code than the actual code itself.

    So I guess I will assume that you are wrong, and just like making outlandish claims on blogs with out any kind of backup links.

  3. Reply Jordan Gray says:

    Nick—I’ll admit, although I was fascinated by the range, intelligence and comprehensiveness of the optimisations (I grinned to see that they were replacing “1000″ with “1e3″, and actually gasped to see that the Google compressor was exploiting short-circuit evaluation to avoid two extra bytes), I did expect quite a different article from the title. Like DotNetWise, I thought I was going to see some figures on being run through the three optimisers would impact execution time in browsers.

    So an enjoyable and much appreciated article, but I was a tad bemused when it finished!

  4. Reply Nick Berardi says:

    Hi Jordan,

    It is next to impossible to performance test JavaScript with any exhaustive and pretty graphs. Because at best they would be inconclusive, and at worst down right confusing. This has to do with the individual implementations of the JavaScript engine, each major browser has their own, and each one would differ in what parts of the code they were optimized for and which they fell flat on.

    Not to mention that you probably wouldn’t see any major performance difference between any of these compressions, on the same JavaScript engine, because really performance in the web-browser as illustrated by Steve Souders of Yahoo, more has to do with delivery in downloading and placement on the page, than the actual performance of the JavaScript code written. You should take a look at some of the work he has done on the subject of performance on web pages.

    Even if I was able to show you that one performed better than the other on Firefox, that doesn’t mean that it would be true for Chrome, Safari, Opera, or IE. So it is not like you are going to keep all three copies on your web server and return a different one depending on the browser. That would just be unwise.

    Really I think the confusion of the article title comes from a lack of understanding how how JavaScript is run in the browsers, and the lack of coherence between browsers. It is not like .NET where you will get roughly the same performance on Windows XP as you do on Windows 7.

    I just want to end this rant with a simple analogy of a similar test in the real world that would yield roughly the same type of inconclusive results.

    Which is faster, leather or cloth seats? Lets performance test the seat covers by testing them on a Ferrari, Honda Civic, and Mustang GT Convertible.

    In the case of the above tests the seat covers are the compressed JavaScript code, and the automobiles that they are being tested on are the JavaScript engines of the major browsers.

  5. Reply Jordan Gray says:

    Hi Nick,

    I’m aware that:

    1. JavaScript engines vary extensively in terms of performance;
    2. file size and download time are usually the most serious performance bottleneck on the web; and
    3. placing scripts at the bottom is a best practice because they can prevent parallel downloads.

    Nor was I disputing that in virtually all cases, file size will have a bigger effect on apparent load time. I was just interested in whether any of the optimisations applied by these compressors might have unanticipated effects on performance—as John Resig points out, load time = download time + evaluation time, and I wanted to see if the last term was significantly modified by the new breed of minifiers. The question (at least in my mind) has largely been laid to rest by actually seeing said optimisations, but I guess I was expecting to see a few pretty charts anyway.

    If you assert that any such effects are negligible, I’m willing to take your word for it. I had no plans for forking my minification strategies to target individual browsers (my time is a bit too valuable for that); I was merely curious, and hoping to explain my surprise at not seeing pretty charts rather less presumptuously than DotNetWise. Your blog title is not misleading, but the expectations of some of us who get here certainly are!

  6. Reply Fai says:

    Hi Nick,

    I would have to concur with the other commenters – good article in effects, though I was expecting a few figures on the evaluation time!

    There are (however negligible) trade offs in terms of code size vs evaluation time (i.e. Dean Edward’s packer which whilst offering very decent compression with an unconventional method of reducing code size, came with a ‘lag’ time when decompression).

    Now, I unfortunately still have to support old IE6-based systems which some clients are still forced to run in their corporate environment, which is a side-effect of developing apps for the public-private sector – and older systems exaggerate code execution performance [noticeably in cases] – hence the blog title being of some interest to me.

    Yes of course, I agree that different javascript engines as you correctly assert, vary extensively on performance! However this does not mean some hard figures on how different optimisations affect times are not useful. Otherwise I will happily stick to the tried and tested setup for the present.

Leave a Reply