Async and Defer

One difference between loading files containing JavaScript and loading other files used by a web page is that when a JavaScript file starts to load the rendering of the HTML stops until after the script finishes loading and is run. This was an essential part of web page processing when JavaScript was first introduced because the JavaScript would "interact" with the web page using document.write statements that would generate HTML that would need to be rendered at the spot where the script occurred. The document.write generated HTML would be the next HTML needing to be rendered and so all of the HTML following the script tag would have its rendering delayed until after that was done. As early browsers had no other way to interact with web pages there was no reason to provide any means to skip over this rendering delay if the JavaScript didn't contain document.write statements as any early JavaScript that didn't had no way of interacting with the web page.

With the introduction of the Document Object Model the need for the document.write statement disappeared and the JavaScript could go anywhere in the page as long as it runs after the HTML it needs to interact with has loaded. This means that we don't need to delay the rendering of the HTML and ought to be able to have JavaScript load just the same as any other files attached to the web page. Unfortunately prehistoric JavaScript using document.write statements still exist even though each and every one of them ought to have been rewritten years ago and so browsers still have to delay the rendering of the HTML when they need to download a script just in case the script is one of those that was written for Netscape 2, 3, or 4.

To avoid the rendering delay and because scripts can't run until after the HTML that they interact with has loaded it has become accepted practice to attach JavaScript to the bottom of the HTML just before the </body> tag. This means that your page doesn't start loading the JavaScript until all of the HTML in the actual page has been rendered by the browser.

Since this rendering delay is only needed by prehistoric JavaScript using document.write statements and those pages would break if the default were changed, two new attributes for the script tag were introduced that allow you to tell the browser to not delay the rendering of the HTML because the script doesn't contain any document.write statements that need the rendering to be delayed. With either of the two attributes present in a browser that recognises the attribute the script would load just the same way as other files do without affecting the rendering. The difference between the two attributes is when the JavaScript runs.

The async attribute tells those browsers that recognise it that there is no reason to delay rendering the HTML while the script loads and that the script should run as soon as it finishes loading. By using this attribute you tell the browser both that the script doesn't contain document.write statements, that the script doesn't attempt to reference any of the HTML that follows the script tag and that this script doesn't interact with any other script that is to be downloaded (and which may or may not therefore have finished downloading when this script runs). This attribute is supported by IE10+, Firefox 3.6+, Google Chrome 8+, Safari 5+ but is still not supported by Opera even in version 12.5 and so you can't rely on it being applied by the browser. With some of the major and popular browsers still not supporting the attribute you still need to place your script tags at the bottom of the HTML in order to avoid delaying the rendering of the HTML but including the attribute may speed up the running of the scripts where you have more than one completely independent script attached to the page where this attribute would allow each script to run as soon as it finished loading rather than delaying until after any previously referenced scripts had run (that may be a much larger script and so take longer to download). You can get the equivalent of the async attribute for all browsers simply by using only a single script at the bottom of your web page that dynamically adds all of the script tags that would otherwise be there. Script tags added to a web page by JavaScript are asynchronous by default.

The defer attribute tells those browsers that recognise it that there is no reason to delay rendering the HTML while the script loads but also tell it that the script need not be run straight away but can instead wait for the HTML to finish rendering before it gets run. A script using this attribute could be included anywhere in the HTML and would be able to reference all of the HTML from within the script without needing to test if the HTML has finished loading because the defer attribute guarantees that the HTML has finished loading before the script runs. This attribute is supported by more browsers than the async attribute is because it was implemented earlier. It is supported by IE5.5+, Firefox 3.5+, Google Chrome 8+, Safari 5+ but is still not supported by Opera even in version 12.5. Since we cannot guarantee that the browser displaying the page supports the attribute we cannot guarantee that the HTML will have finished rendering before the script runs unless the script tag is placed at the bottom of the page (where we would place it so as to allow the page to appear to load faster anyway). If the script tags are placed at the bottom of the HTML then the defer attribute would make little difference to the actual loading and running of the script since there is no HTML after the script tag for the script to wait to be rendered.

Note that these attributes where supported only affect external scripts as scripts embedded into the HTML itself will be loaded with the HTML and run as soon as they finish loading. You can therefore achieve the same result as these attributes provide simply by having JavaScript embedded in the HTML to dynamically add the script tags. If you instead decide to use the attributes themselves then you will only gain the benefits that the attributes provide in those browsers that support the attributes. Given that we don't really need the defer attribute if we place the script tags at the bottom of the page we would achieve the best result once everyone is using browsers that support the async attribute by attaching our scripts to the bottom of the web page in HTML 4/5 using:

<script type="application/javascript" async src="myscript.js"></script>

or in XHTML 1.0/5 using:

<script type="application/javascript" async="async" src="myscript.js"/> 

(Note that by the time everyone is using browsers that support the async attribute they will also be using browsers that support JavaScript and so the deprecated type="text/javascript" that is necessary to allow IE8 and earlier to run the script as JScript because they don't support JavaScript would no longer be necessary either and so the correct MIME type for JavaScript will be able to be used).

 

This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow
Donate