JavaScript/HTML Synchronous and Asynchronous Loading

To complement my previous article about implementing a JavaScript include facility, I’m taking a closer look at the default behaviour of JavaScript and HTML (including HTML5) with respect to synchronous and asynchronous loading of script files (among other things). If you’ve ever wanted to include script files within an HTML page in an asynchronous way, or you’ve wanted to load a file synchronously using JavaScript, this article may well be of use to you.

Disclaimer

As included in the first JavaScript include article, I invite you to read my disclaimer. It still applies, and constructive comments are welcome on any gaffes or oversights.

Synchronous to Asynchronous

When a JavaScript source file is included in a web page via HTML’s ‘<script>’ tag, the loading of the included file is performed to completion before any more of the including page is rendered/executed. That’s what synchronous loading is.

For the most part, synchronous loading is a useful way to operate for included JavaScript code files, and it seems likely that, even if most beginner JavaScript programmers are largely unaware of the whole sync/async situation, they will develop web pages happily making the (perhaps unknowing) synchronous-loading assumption.

A common case is when including a library of functions for use within the current page, as in the following snippet:

<script type="text/javascript" src="usefulLib.js"></script>

<script type="text/javascript">
    usefulFn(); // Function from 'usefulLib.js'.
</script>

It seems sensible to expect that, by the time we get to the call to ‘usefulFn()’, that ‘usefulLib.js’ (including the code for ‘usefulFn()’) would have fully loaded. In fact, it would be a nuisance if we couldn’t rely on this being the case. Imagine if, at the whim of the browser, or other happenstance, it was sometimes the case that ‘usefulFn()’ wasn’t available to call after ‘usefulLib.js’ had been requested for inclusion.

Sometimes, however, we may specifically want JavaScript source files to load asynchronously, i.e., for our including page to carry on rendering/executing while at the same time loading the specified included file. Alternatively, we may wish to include a JavaScript source file only after the including page has finished loading. This may be handy for files from external sources where we don’t want our including page to suffer the consequences of: slow connection speeds, heavily loaded external servers, or waiting for timeouts on external servers that aren’t even there at the moment.

For these cases, the HTML ‘<script>’ element has the ‘defer’ and ‘async’ attributes (the latter introduced in HTML5). In short, ‘defer’ requests that the loading of the specified file occurs after the including page has finished loading, and ‘async’ requests that the loading of the specified files occurs concurrently with (or, at least, independently of) the including page.

These attributes may be used in a similar manner to any HTML attributes, e.g.:

<script type="text/javascript" src="usefulLib.js" defer></script>
<script type="text/javascript" src="usefulLib.js" async></script>

Sync to Async Example Code

To see the ‘defer’ or ‘async’ attributes in operation, create a separate JavaScript source file (let’s call it ‘busy.js’) containing the following code:

var startNow = new Date();
var pauseFor = 5000; // In milliseconds.

while (new Date() - startNow < pauseFor)
    ;

This code causes JavaScript to go into a busy 'while' loop until at least a certain number of milliseconds have elapsed (in the code above, it's 5000 milliseconds, or five seconds).

Having saved this JavaScript file, create an HTML page containing the following:

<html>
<head>

<script type="text/javascript" src="busy.js"></script>

<script type="text/javascript">
alert("Time's up");
</script>

</head>
</html>

If you browse to this page, you should experience a five-second pause after which the 'Time's up' alert box will pop up. This shows that, by default, the HTML '<script>' tag loads and runs the specified source file to completion before proceeding with rendering/executing the including page.

Now tweak the first of the '<script>' lines above to include the 'async' attribute, like this:

<script type="text/javascript" src="busy.js" async></script>

If, after this edit, you refresh the page (and assuming you have a browser that supports HTML5), you should see the 'Time's up' alert pop up immediately, while the 'busy.js' code runs independently.

JavaScript's Asynchronous Behaviour

Because of the danger of poor performance, JavaScript itself tends to favour asynchronous working, generally avoiding synchronous behaviour. As an example of this tendency (and as a exercise to the reader with a little spare time) try to find a means of having JavaScript perform a blocking wait or sleep. (To repeat: that's a blocking, not busy, wait, so I don't mean a 'while' loop like the one in my 'busy.js' example that keeps your processor busily running for five seconds.) If you find a nice way for JavaScript to perform blocking wait, do let me know.

To see JavaScript's default asynchronous behaviour, create a new HTML page containing the following code:

<html>
<head>

<script type="text/javascript">
function loadJavaScript(filePath)
{
    var headElement = document.getElementsByTagName("head")[0];
    var newScriptElement = document.createElement("script");
    newScriptElement.type = "text/javascript";
    newScriptElement.src = filePath;
    headElement.appendChild(newScriptElement);
}

loadJavaScript("busy.js");
alert("Time's up");
</script>

</head>
</html>

This is essentially the programmatical equivalent of an HTML '<script>' tag. As you can see, I've provided a JavaScript function that finds the containing page's '<head>' element, and dynamically adds to it a new 'text/javascript'-type '<script>' element that has a 'src' attribute of a supplied value. Having defined this function, I call it with the name of the 'busy.js' source file we used earlier, then pop up the 'Time's up' alert box.

If you browse to this page (and you created the 'busy.js' script file earlier), you will see that the 'Time's up' message pops up immediately, showing that, unlike the HTML version we saw previously, JavaScript's default behaviour is asynchronous.

Synchronous File Loading in JavaScript

As we've already established, there are good reasons for generally favouring asynchronous behaviour. Putting the rendering of your web page on hold waiting for some external file to load (which may be on another server on the other side of the world, and which may not even be available at the moment) isn't always the smartest move. Sometimes, however, being able to (for example) load a file synchronously is just what's required.

I recently encountered such a case in implementing a source-code inclusion facility in JavaScript (which you can read about in my first JavaScript Include article).

In this case, I resorted to the use of AJAX to read (and include) the contents of source files synchronously for precisely the same reasons that the HTML '<script>' tag defaults to being synchronous: because I want to be able to rely on included code being available to me immediately after including it.

Here's a synchronous version of the previous example:

<html>
<head>

<script type="text/javascript">
function loadJavaScriptSync(filePath)
{
    var req = new XMLHttpRequest();
    req.open("GET", filePath, false); // 'false': synchronous.
    req.send(null);

    var headElement = document.getElementsByTagName("head")[0];
    var newScriptElement = document.createElement("script");
    newScriptElement.type = "text/javascript";
    newScriptElement.text = req.responseText;
    headElement.appendChild(newScriptElement);
}

loadJavaScriptSync("busy.js");
alert("Time's up");
</script>

</head>
</html>

This snippet should work fine (and, if it doesn't, see the 'Note About Local Files' below), but it's pretty pared down: it has no error checking and other fail-safes. For a more bullet-proof implementation of synchronous JavaScript file reading, I invite you to see one used as part of the first JavaScript Include article I mentioned earlier.

A Note About Local Files

For security reasons, some browsers (and it's amazing that it's not all browsers) won't allow the reading of files using the 'file:///' protocol in AJAX. If you're having difficulties (specifically seeing messages like 'XMLHttpRequest cannot load file:///...' in your JavaScript console), you'll need to access the code via HTTP, i.e., via the use of a web server, instead of just double-clicking your example pages (or equivalent means of quickly loading them into your browser).

Improved Include

Just as a further comment to my previous JavaScript Include article, it is still my intention to write further include-related articles to overcome the issues identified with the first include implementation presented there.

5 thoughts on “JavaScript/HTML Synchronous and Asynchronous Loading”

  1. I’ve been playing with Javascript for 4/5 years and I have to say, I didn’t know the async and defer attributes existed even in HTML5. Very useful to know, I hate putting Javascript at the bottom of my page, just seems like such an illogical place to include a file when everything else is put at the top.

    Can’t say I deal with much raw JS these days, I tend to do everything through jQuery where possible. It makes life so much easier and using a CDN means very little bandwidth footprint as most users have it cached from another site. Granted this is about concepts, so of course raw is best rather than teaching a library on top!

    Speaking of asynchronous shenanigans in Javascript, while not specifically about loading the files… Sockets.IO! You can do some amazing stuff with non-blocking, event-driven web-socket ‘pipelines’ using that library. Generally the socket server is Node.JS, then you can just throw data down it to clients (broadcast or specific) and it can be bound to an event on the client-side stupidly easily.

  2. Good article.
    I wanted to say that this:

    function loadJavaScript(filePath)
    {
    var headElement = document.getElementsByTagName(“head”)[0];
    var newScriptElement = document.createElement(“script”);
    newScriptElement.type = “text/javascript”;
    newScriptElement.src = filePath;
    headElement.appendChild(newScriptElement);
    }
    loadJavaScript(“busy.js”);
    alert(“Time’s up”);

    doesn’t prove the async behaviour of JavaScript but only that script added after the page was loaded is loaded async (and to better show that you need at least 2 scripts loading at the same time).
    Why doesn’t prove the async behaviour?
    When this line is done :headElement.appendChild(newScriptElement); JavaScript is done working and the rest (the loading proccess) is not JavaScript.
    So after calling loadJavaScript(“busy.js”); it is expected to see
    alert(“Time’s up”); immediately.

Leave a Reply

Your email address will not be published. Required fields are marked *