When is javascript executed?

I do not know why I never considered when javascript code is executed on a webpage, but it is indeed an important issue. Consider the following example:

<html>
<head>
<script>
document.getElementById("div1").textContent="hello";
</script>
</head>
<body> 
<div id="div1"></div>
</body>
</html>

You will get this error:

TypeError: document.getElementById(…) is null

The problem persists if you move the script tag from the head tag to the body tag:

<html>
<head>

</head>
<body> 
<script>
document.getElementById("div1").textContent="hello";
</script>
<div id="div1"></div>
</body>
</html>

The problem does not disappear unless you move the script tag after the div as follows:

<html>
<head>

</head>
<body> 
<div id="div1"></div>
<script>
document.getElementById("div1").textContent="hello";
</script>
</body>
</html>

This hints that knowing when the script is executed is important. The rule is simple: when the html parser meets the script, it executes the code. After executing the js code, the parser continues to parse the following html content. So, if the js code uses html elements after the script tag, the execution would fail because the html elements are not available yet. This rule also applies to external javascript scripts:

<html>
<head>
<script src="https://myprogrammingnotes.com/some.js"></script>
</head>
<body> 
<div id="div1"></div>
</body>
</html>

The actions a browser does are:

  1. download the html page.
  2. after downloading, parse the html content.
  3. the parser meets the script tag.
  4. the parser downloads the external js script.
  5. the parser executes the code of the js script.
  6. after execution of the js code, the parser continues to parse the following html content.

This is called synchronous loading/executing of js, which blocks the rendering of the following html content. By adding the defer or async attribute to the script tag, you can opt in asynchronous loading/executing of external javascript scripts.

<html>
<head>
<script async src="https://myprogrammingnotes.com/some.js"></script>
</head>
<body> 
<div id="div1"></div>
</body>
</html>

Now, after downloading the html file, the parser begins to parse it. When it meets the script tag, it begins to load the external script, and parses the following content in parallel. The async script gets executed right after it is downloaded(do not care how far the parser goes for the following content).

If async is replaced by defer, the script is also downloaded in parallel as soon as the parser meets the script tag. But if the script is downloaded before the following html content is parsed, it won’t be executed immediately, but rather wait for the whole html is parsed, then executed. After the script is executed, theĀ DOMContentLoaded event is fired. Multiple defer scripts keep their execution order(while async scripts do not keep the order).

External css is also loaded synchronously by default. Although there is no defer/async attribute for css link tag, you can also implement an asynchronous css using this trick.

If you like my content, please consider buying me a coffee. Buy me a coffeeBuy me a coffee Thank you for your support!

Leave a Reply