JavaScript loading and execution order

It is necessary to care about the order of loading and execution of scripts inside a HTML file. In this article you will get to know whether a JavaScript file’s loading is blocking or not, its execution is before or after parsing any subsequent HTML content, how to load JavaScript asynchronously, how to defer its execution until the page has finished parsing, etc.

Basic script element

When below script element appear in a HTML file:

<script src="alert1.js"></script>

or

<script>
  alert('inline-js');
</script>

The browser will load and execute the script immediately, block parsing. That means if the script code operates any HTML element that appears after it, it will fail because the element has not been parsed yet.

That’s why an old suggestion recommends putting the script elements at the bottom of the document. Now it is not a good idea (the script’s loading/parsing is blocked until the HTML has been loaded), with defer you can load scripts without blocking parsing and defer the execution until the document finishes parsing

Dynamically created script

alert("inline-js2") in below code is counted as ‘inline’ scripts too and will get compiled and execute immediately.

<script>
  const script = document.createElement('script');
  script.textContent = 'alert("inline-js")';
  document.body.appendChild(script);
</script>

async in script element

<script async src="alert1.js"></script>

In the example above, the async attribute indicates that the script will be loaded in parallel to HTML parsing and executed as soon as it is available. The script execution will block the page from rendering. That means its loading will not block the subsequent HTML parsing, and its execution maybe before the HTML paring completes.

If the async is present on a module script element like below, the script and its dependencies will be fetched in parallel to HTML parsing, and the module script will be executed as soon as it is available.

<script async type="module" src="a.js"></script>

Dynamically created script

alert4.js in below example is async because the scripts created from script default to async. See more at MDN: Async scripts.

<script>
  const script = document.createElement('script');
  script.src = 'js/alert4.js';
  document.body.appendChild(script);
</script>

Note

In the above example, if the script element is inserted using the innerHTML and outerHTML attributes, it does not execute at all.

 
   const e = document.createElement('div');
   e.innerHTML = '';
   document.body.appendChild(e);
 

document.write() (Strongly discouraged to use)

document.write() can be used to write a string text to the document. Its usage is strongly discouraged for it has very idiosyncratic behavior.

Note

The execution order of multiple async scripts is not guaranteed as the order they appear in the document.

All major browsers have supported async.

defer in script element

The defer attribute has a similar effect when it comes to loading in parallel. But the script will be executed after the document has been parsed, but before firing DOMContentLoaded event. That means a deferred script will prevent the DOMContentLoaded event from firing until the script has loaded and finished execution.

A module script is deferred by default, therefore there is no need to use the defer for it.

Both asnc and defer work with external files which means the src is set to a file in the script element. Otherwise these attributes would have no effect.

Note

The execution order of multiple defer scripts is the order in which they appear in the document.

All major browsers have supported async.

Summary

The loading and execution order of script is summarized as below diagram which is from HTML Standard – the script element.

JavaScript loading and execution order

Below is an example that helps you to observe the loading and execution order. In the example, each alertx.js has just one line of code: alert('alert-x');.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript loading and execution order</title>
    <script src="js/alert1.js"></script>
    <link href="css/main.css" rel="stylesheet">
</head>
<body>
    <script defer src="js/alert2.js"></script>
    <script async src="js/alert3.js"></script>

    <script>
        alert('inline-alert-1');
    </script>

    <script>
        const script = document.createElement('script');
        script.textContent = 'alert("inline-alert-2")';
        document.body.appendChild(script);
    </script>

    <script>
        const script2 = document.createElement('script');
        script2.src = 'js/alert4.js';
        document.body.appendChild(script2);
    </script>

    <h1>Hello world!</h1>
    <script>
        alert('inline-alert-3');
    </script>
</body>
</html>

References