Deferred Javascript

Filed: Thu, May 03 2007 under Programming|| Tags: trick tip hack javascript defer load

Fair warning: although it is defined by the HTML 4.01 standards, only Internet Explorer 4.0 and higher implements the technique described in this article.

One of the most overlooked, and powerful, features when defining Javascript in your page (either externally or in-line) is the defer attribute. By adding a defer attribute to your <script> tag you are telling the browser that it can wait until it's done setting up the rest of the page before doing anything with the Javascript block.

The problem with Javascript is that when the browser is loading the page, whenever it comes across a <script> tag, it stops, it loads the external script (if there is one), it evaluates the script, and it runs it before returning to the task of rendering the web page. This can impact page performance, making your site sluggish and slow-to-load, especially if you have multiple script blocks in your page.

The best practice theory is that you want to put all your Javascripts at the end of the HTML, either right before the </body> tag, or right below it in a second <head> area. (Yes! You can indeed have a second <head> section below the body. In fact, Microsoft recommends it to work around certain caching issues).

Unfortunately, even the best attempts at this sort of optimization leave a page littered with javascript blocks throughout the page. It's very hard to maintain a coherent block of code inside the HTML. That was the reasoning and rational for the defer attribute.

With a defer attribute you can define all your code in one block and simply mark it as defer, which would have the same exact effect of moving all your code to the bottom of the page, regardless of where it actualy resides.

For instance...

<script type='text/javascript' src='common.js' defer='defer'></script>

Here, the defer attributes tells the browser to wait until it has finished loading and building the page before it will execute the code found in common.js. A lot of organizations like to keep as much Javascript as possible in the <head> area of the page (inertia is a horrible thing!) so if you're stuck by ancient rules like this or you just want to enforce some standard readability on your pages, the defer attribute will let you put your code where it makes sense to you and still have the page load optimally.

The defer attribute works on both in-line and external scripts.

<script type='text/javascript' src='common.js' defer='defer'></script>

<script type='text/javascript' defer='defer'>
   // This inline script is deferred.
</script>

There is a very good and thorough analysis, detailing exactly how Internet Explorer handles script deferral here: http://www.websiteoptimization.com/speed/tweak/defer/. This article is actually several years old but the information is still current through Internet Explorer 7.0

Unfortunately, defer is supported only in Internet Explorer right now even though it is a part of the official 4.01 specification. Mozilla is aware of the problem as there's a seven year old open bug tracking it. Additionally the whatwg (the advisory body working on the next generation of HTML) has more fully described how defer should behave in future browser versions.

If you check out the whatwg page you'll see that there's also an async attribute in the pipes (tubes?) which will tell the browser to initiate the loading of the script and then continue to build the page, executing the script only after it's finished loading. ( A nifty feature in its own right! )

Even though defer doesn't work in Firefox and Opera right now, they will simply ignore the attribute. As this attribute becomes fully supported these browsers will eventually benefit from the page optimization just like IE.

If you're comfortable with advanced Javascript (and if you're actively seeking out power-optimizations like defer, you should be!) you can provide full compatibility work around the defer attribute by dynamically loading scripts after the page has loaded. While not as elegant and simple as defer, it is more compatible with today's browsers. I would personally recommend dropping in a defer on casual pages just to get in the habit (it's doubtful mozilla will let another version of HTML go by without implementing the published specification), while using dynamic loads on larger web-apps where the size and weight of the script can bog down a page and you're looking to eek out every last bit of efficiency you can.

Just one more tool for your toolbox. Happy coding!