20 Jan 2010

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

6 Comments Review

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?

18 Jan 2010

Yahoo YUI Compressor vs. Microsoft AJAX Minifier vs. Google Closure Compiler

11 Comments Review

A little more than a year and half ago I created a MSBuild Task for the YUI Compressor that was very well received, and even highlighted on the YUI Compressor site.  At the time of writing that article YUI Compressor was king of the hill, and for the most part the only game in town that was really designed for production level use.  Since then a number of new competitors have been released by Google and Microsoft, and I wanted to see how they stacked up against the YUI Compressor.

Setup

For these tests I wanted to test a pretty complex set of JavaScript to really stretch the limits of each of the optimizers. So I choose jQuery 1.4 as the subject for the tests.  I choose jQuery for many reasons, but the biggest is because it is very well known set of code for most developers, and it would be very easy for anybody to test in their applications.

The setup of my machine is as follows:

  • Windows 7 Pro (x64)
  • Java 6 Update 17
  • .NET 3.5 SP1

Each optimizer and the version:

Testing

I ran the following from the command line on jQuery 1.4 raw source code to produce the following files.  Here is the raw source code file that I used in my testing:

Microsoft
ajaxmin jquery-1.4.js -o microsoft.js
Microsoft (Hypercrunch)
ajaxmin -h jquery-1.4.js -o microsoft-h.js
Microsoft (Hypercrunch Combine Literals)
ajaxmin -hl jquery-1.4.js -o microsoft-hc.js
Google (Whitespace)
java -jar compiler.jar --compilation_level WHITESPACE_ONLY --js jquery-1.4.js
Google (Simple)
java -jar compiler.jar --compilation_level SIMPLE_OPTIMIZATIONS --js jquery-1.4.js
Google (Advanced)
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js jquery-1.4.js
Yahoo
java -jar yuicompressor-2.4.2.jar jquery-1.4.js -o yahoo.js
Yahoo (Minified Only)
java -jar yuicompressor-2.4.2.jar jquery-1.4.js --nomunge -o yahoo-m.js
Yahoo (Disabled Optimizations)
java -jar yuicompressor-2.4.2.jar jquery-1.4.js --disabled-optimizations -o yahoo-o.js
Yahoo (Preserve Unnecessary Semicolons)

java -jar yuicompressor-2.4.2.jar jquery-1.4.js --preserve-semi -o yahoo-s.js

Results

The above testing produced the following results.

  Size (bytes) Command Options Size Optimization Place
jQuery 158407   100.0000%
Microsoft 93814   59.2234% 8
Microsoft (Hypercrunch) 70156   -h 44.2884% 4
Microsoft (Hypercrunch Combine Literals) 67149   -hc 42.3902% 2
Google (Whitespace) 94225   –compilation_level WHITESPACE_ONLY 59.4829% 9
Google (Simple) 69467   –compilation_level SIMPLE_OPTIMIZATIONS 43.8535% 3
Google (Advanced) 63384   –compilation_level ADVANCED_OPTIMIZATIONS 40.0134% 1
Yahoo 76453   48.2636% 5
Yahoo (Minify Only) 94843   –nomunge 59.8730% 10
Yahoo (Disabled Optimizations) 76465   –disable-optimizations 48.2712% 6
Yahoo (Preserve Unnecessary Semicolons) 77384   –preserve-semi 48.8514% 7

The results are pretty clear of who won the top prizes in the above results.  Out of the top 5 ranking outputs Google and Microsoft both took two of the positions and Yahoo took 1. Google Closure Compiler placed first when the Advanced Options were enabled which did really surprise me that much, and Microsoft AJAX Minifier placed second when Hypercrunch and Combine Literals were turned on.  The Microsoft ranking, however was very surprising to me because of the lack-luster reviews of RC6 that was released back in October.

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

Because of how the file is being optimized, it alters your code and would require you to do extra testing before deployment and it would make the resulting output almost impossible to debug against your un-minified version.  So for these reasons it may not be the best choice, if you value ease of testing over byte size of your files.

So which ever option out of Microsoft, Google, or Yahoo you decide to use, all will produce a much more optimized-for-size file than the original. And, in my opinion, if you are already using Yahoo in your build environment there really isn’t much of a reason to switch, unless you are in the top tier of websites and need to squeeze every byte out of the file for delivery over the internet.

Personally, I am going to keep using YUI Compressor, because it has been rock solid in producing minimized and obfuscated code for my current projects, but in the future I may consider going with Microsoft or Google depending on what I am trying to accomplish.

12 Nov 2009

Create an attractive loading panel in jQuery

5 Comments How To, Programming

One of the important things about web programming, especially when using AJAX, from a usability standpoint is to provide a responsive user interface to the audience.  This level of responsiveness to the user’s actions can be achieved in many different ways; showing messages, changing colors, adding animation, changing contexts, basically anything that provides a natural transition from the action performed by the user to the reaction by the application to indicate that their action is actually causing something to happen.

One of the companies that has gone way beyond standard application responsiveness is a company called thirteen23.  They put an amazing level of detail and thought in to every action that the user performs.  A great example of their skilful approach to application development is a WPF Twitter client they call Blu.  An example of the level of thought they provide is their reply feature they offer.

thirteen23_blu

Not only are they solving a problem with this user interaction, but they are providing a feedback mechanism, with animation and context switching, to the user.  If you haven’t already download the Blu client, you should definitely take a look at it, and notice all the subtle usability features that make it a really great tool.

A feeback mechanism we all can do

I don’t even think I could achieve what thirteen23 has achieved with Blu or even write up a good blog post about everything they have done right with this Twitter client.  But one thing that I can do is show you how you can add an attractive loading panel to your website, with relatively no effort and that will provide ample feedback for your users during an AJAX request.  For my example I am going to be using jQuery, but what I am showing you is easily ported to other JavaScript frameworks.

The example

The first thing I have is this pretty graph with a couple of inputs and an Update button.

graph

When I click the update button is does a standard jQuery.get(…) command against my web server to pull the new graph data.  However depending on the date range, which dictates the number of plot points I need to pull for the graph, it can take anywhere from a half second to 5 seconds to pull all the data necessary to show the graph. A half second isn’t bad, because that is just about fast enough where they consider the new graph showing up a adequate response to their action of clicking the Update button.  However 5 seconds is really pushing their patients.  So in order to give the feeling of something is really happening because of their button click, we need to provide a feedback mechanism.  The feedback mechanism I choose to implement was a standard loading window.

First things first

The first things we need to do is setup the necessary HTML elements and CSS styling.  Before I went off and added in my HTML and CSS, I first needed to pick out a loading animated image that I liked and worked with the look and feel of the website.  Lucky for me there is a great AJAX Loader generator at a site called http://www.ajaxload.info/.

After I found the image I was interested in using with my website, I then needed to add the HTML.  The first thing I needed to do was create the desired content area, or update pane, that would be the focus area of the update.  I did this by creating a wrapper around my graph, called report-pane, and then added an element called report-loading, which would be the loading window that would be styled by the CSS.

<div id="report-pane" style="position: relative;">
	<div id="report-loading" class="loading"><img src="/Content/images/ajax-loader.gif" width="32" height="32" /><br /><strong>Loading</strong></div>

	<!-- report here -->
</div>

The next thing I did was add in the CSS that would render my loading window in an appealing way that fit in to the design of the site.

/*  Loading
**********************************************************************/

.loading {
	position: absolute;
	display: none;
	border: 1px solid #5c9ccc;
	padding: 2px;
	background-color: #5c9ccc;
	color: #ffffff;
	opacity: 0.90;
	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	width: 100px;
	height: 50px;
	text-align: center;
	z-index: 100000;
}

After I had the necessary markup and styles in place, the update-loading element I added to the HTML looked like this:

loading_panel

Now I can move on to creating the actual user interaction.

Enter jQuery

jQuery has a couple nice global events that trigger whenever an AJAX request being made.  The two we are going to use today are called ajaxStart and ajaxStop.  The method names are a pretty good indicator of their functionality, so I won’t bother going in to detail.

The actual jQuery JavaScript code for getting this to display is pretty trivial.  Which speaks more to the power and flexibility of jQuery, more than anything else.

$("#report-pane").ajaxStart(function() {
	var width = $(this).width();
	var height = $(this).height();

    $("#report-loading").css({
		top: ((height / 2) - 25),
		left: ((width / 2) - 50)
    }).fadeIn(200);    // fast fade in of 200 mili-seconds
}).ajaxStop(function() {
	$("#report-loading", this).fadeOut(1000);    // slow fade out of 1 second
});

There are two things you should pay special attention to in the above code.  The first is the fact that I want the loading screen to be positioned in the center of the graph so that, so that it is very apparent to the user what is being updated, and because their attention is already on the graph as the main focal point of their clicking of the Update button.  I do this by taking half the width and height of the report-pane and subtracting the size of the report-loading box, this will give me the x and y coordinates at which to place the report-loading box inside the report-pane.

The second thing you should take note of is that I do a quick fade in of 200 mili-seconds, so that the loading box appears almost instantaneously after they have clicked the Update button.  However on the face out, after the AJAX request has finished, I want them to really notice that the action has completed so I make the face-out 5 times longer than the fade in.  This provides enough time for them to notice that the action has completed and that the plot points being shown in the graph have been updated.

Final Result

And here is what the final result looks like, after adding only a handful of code to my already existing application.

graph_loading

Not bad huh?  And it didn’t even require any process change to my already working application.  It was really that easy, so you really have no excuse for not adding a little flare and usability to your web application.  Your users will thank you by lowering their anxiety level a little by not having to wonder if that button they just clicked actually did anything.