So you created that nice website or web application and would like to go a step further in optimizing the front-end loading time? With some great free tools you can easily optimize your javascript to load 2 or 3 times faster if you are willing to trade the regular way of embedding javascript file.

Loading script asynchronously

One thing you need to know is that your script tag block the rendering of your page. In fact, it blocks literally anything from happening, when you are downloading and executing one script, not one css file or one image is downloaded. So imagine you got 10 script files loaded in your head with around 300k in size, well the browser need to load them one by one (well in fact 6 at a time in FF and WebKit, and as many as 18 (or more) in IE8. In older browsers it will be one at a time. ), and execute them one by one, by that time there is a good chance your page would have already render the HTML and CSS.

The first and very easy thing you can do is loading them just before the body end.

<script type="text/javascript" src="/js/jquery/jquery-1.3.2.min.js"></script> <script type="text/javascript" src="/js/jquery/jquery.json-2.2.min.js"></script> <script type="text/javascript" src="/js/jquery/plugins/formvalidator/jquery.validationEngine.js"></script> </body> </html>

That way, at the very least, the CSS and the html will be loaded before the javascript. One thing really cool about doing this is that the jQuery DOM ready statement becomes obsolete. Your html is already ready because you parsed it before any script tag. That being said, watch out for the global scope, I would still wrap my script in an anonymous self-executing function, like this:

(function () { add script here ... })()

Going one step further with labJS

With LABjs you can load your js files completely asynchronous. The difference with the previous example is that even if your scripts are at the bottom, they are still downloading one by one. With this tool, you can load your scripts simultaneously and specify an executing order. From my tests with dynatrace, the javascript load 3x more rapidly using LABjs, and my page is loading 15% faster (for about 15 js files) on IE8. An example:

<script src='/js/LAB.min.js'></script> <script> $LAB .script("/modules/comment/front/js/comment.js") .script("/modules/core/commun/js/common.js") .script("/modules/core/front/js/custom.js") </script> </body> </html>

Your loading speed gains comes with a cost of complexity. As I said earlier, it loads them async, so any of them could be executed before another. This is pretty bad if you use a library like jQuery, it needs to be executed first. You have 2 choices here, use .wait() at the end of each script that need to preserve the execution order, or use .setOptions({AlwaysPreserveOrder:true}) that will always preserve the order at a small cost of performance. So if you want to go all gun blazing use .wait(), if not, use AlwaysPreserveOrder (that’s what I do, the speed cost is really minimal). Some examples:

With .wait()

<script src='/js/LAB.min.js'></script> <script> $LAB .script("js/jquery/jquery-1.4.2.min.js").wait() .script("js/jquery/jquery-sortable-1.7.1.custom.min.js") .script("js/jquery/jquery.json-2.2.min.js").wait() .script("js/jquery/common.js") </script> </body> </html>

With AlwaysPreserveOrder

<script src='/js/LAB.min.js'></script> <script> $LAB .setOptions({AlwaysPreserveOrder:true}) .script("js/jquery/jquery-1.4.2.min.js") .script("js/jquery/jquery-sortable-1.7.1.custom.min.js") .script("js/jquery/jquery.json-2.2.min.js") .script("js/jquery/common.js") </script> </body> </html>

The full labJS solution

Okay we figured out our execution order, what about our inline scripts? Those scripts block will probably be executed before any js file has been downloaded. Well the solution to this is cool, but not simple. We will create a global variable that will contain all our inline coding. To do that the first thing to do is add a variable to the head.

<script> var _loadingQueue = []; // declare our array</script> </head>

Now in any part of your page, you could add an inline script block this way:

<script src='/js/LAB.min.js'></script> <script> _loadingQueue.push(function(){ $("body").html("this is loaded from an inline script block") }); </script>

As you can see I use jquery in there, _loadingQueue.push will add this anonymous function to our loading queue, you can have as many inline scripts as you want.

In our labjs loading sequence, we need to do a bit of hacking to make this work.

<html> <head> <script> var _loadingQueue = []; // declare our array</script> </head> <body> <randomHtmlTags..............> <script> _loadingQueue.push(function(){ $("body").html("this is loaded from an inline script block") }); </script> <randomHtmlTags..............> <script src='/js/LAB.min.js'></script> <script> var $LoadDefer = $LAB .setOptions({AlwaysPreserveOrder:true}) .script("js/jquery/jquery-1.4.2.min.js") .script("js/jquery/jquery-sortable-1.7.1.custom.min.js") .script("js/jquery/jquery.json-2.2.min.js") .script("js/jquery/common.js"); .wait(function(){ framework.doSomething(); }); if( typeof( window[ '_loadingQueue' ]) != "undefined"){ for(var i=0,len=_loadingQueue.length; i<len; i++){ $LoadDefer = $LoadDefer.wait(_loadingQueue[i]); } } </script> </body> </html>

As you can see I have a nice loop now. If the variable _loadingQueue exists, I get the _loadingQueue length and when all my scripts are loaded and executed ( $LoadDefer.wait). I execute all my stored functions. Pretty nice!

This is the full solution to load asynchronously your scripts, I think it will cover 99% of your needs. I added a demo below.

View demo

Combining and minifying your scripts

Something you might not notice in your local development is that file requests are time consuming. Imagine you have 10 js files in your page, if your browser spend 100ms on the network looking for each script, you lose a complete second just looking around the web for those files!

Enter minify

Minify is a nice php library that let you combine your css and js files on the fly and cache them on your server. With this library, you could get back this 1 second.

Minify is easy to install, you download it, put it at your address root, from there you can simple access minified files like this http//www.example.com/min/?f=js/jquery/jquery-1.4.2.min.js,js/jquery/jquery-sortable-1.7.1.custom.min.js. At my workplace, we use minify on pretty much every generic plugins and components that we are using in a given site. This is a good compromise, this way we have about 10 javascript files combined and we can still see errors online from our custom scripts. But you could simply combine all the files for maximum performance, at the cost of losing errors location.

You might get a bit lost in the config, the 2 really important configuration are $min_cachePath and $min_documentRoot. I had to work a bit to get minify working with the Zend framework.

Integrating it with labJS

Once minify works, adding it is not really complicated.

<script src='/js/LAB.min.js'></script> <script> var $LoadDefer = $LAB .setOptions({AlwaysPreserveOrder:true}) .script("/min/?f=js/jquery/jquery-1.4.2.min.js,js/jquery/jquery-sortable-1.7.1.custom.min.js"). .script("js/jquery/common.js") if(_loadingQueue){ for(var i=0,len=_loadingQueue.length; i<len; i++){ $LoadDefer = $LoadDefer.wait(_queue[i]) }} </script>

Small warning

I do not use minify to combine my css files, simple because it brakes my images path. If you always use absolute path you will have no problem, but remember that most of your jQuery plugins use relative paths in their css.

Conclusion

Optimizing is not free, it comes with adding a layer of complexity to your application, personally I created a small helper for Zend framework that incorporate everything I mentioned above. From one boolean variable I can decided if I want to minify and embed using labJS. This is really useful for debugging. Also if you are interested in optimizing your js I would strongly recommend you have a look at the api of both LABjs and minify for more options and more detailed instructions.

Some other technologies worth mentioning, YUI compressor as a replacement for the minify library, and requireJS as a replacement of LABjs. requireJS got a different approach, instead of focusing on loading asynch our files, it focus at loading only the files you need to execute a given script in the page.

Small clarification from James Burke : RequireJS also loads files asynchronously. As compared to LABjs, RequireJS encourages writing well-scoped modules, and using its built in optimization tool to combine and minify scripts.



Dynatrace



Dynatrace is really the tool for testing front-end performance on internet explorer, you get execution times from everything, cpu usage and much more. It is the most powerful tool I saw on any platform for front-end tracing. The best part? It’s completely free!