Best Practice: Where to include your <script> tags

I have read in some places that for best performance we should include <script> elements at the end of our body tags, also, I have read that it's best practice to include at the end of our html OUTSIDE the <body> element. Now, I'm reading that the best practice is to include <script> elements on your head and just add 'async' at the end of it (HTML5 Only).

Is the last statement correct? What is the truly best practice when adding <script> elements to our markup? A lot of the information on the web seems outdate (2009-2011) when it comes to this topic.

Thanks!

2 Answers

Fetch the HTML page (e.g. index.html)
Begin parsing the HTML
The parser encounters a <script> tag referencing an external script file.
The browser requests the script file. Meanwhile, the parser blocks and stops parsing the other HTML on your page.
After some time the script is downloaded and subsequently executed.
The parser continues parsing the rest of the HTML document.
Step 4 causes a bad user experience. Your website basically stops loading until you've downloaded all scripts. If there's one thing that users hate it's waiting for a website to load.

Why does this even happen?

Any script can insert its own HTML via document.write() or other DOM manipulations. This implies that the parser has to wait until the script has been downloaded & executed before it can safely parse the rest of the document. After all, the script could have inserted its own HTML in the document.

However, most javascript developers no longer manipulate the DOM while the document is loading. Instead, they wait until the document has been loaded before modifying it. For example:

// my-script.js
document.addEventListener("DOMContentLoaded", function() {
// this function runs when the DOM is ready, i.e. when the document has been parsed
document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});
Because your browser does not know my-script.js isn't going to modify the document until it has been downloaded & executed, the parser stops parsing.

Antiquated recommendation

The old approach to solve this problem was to put <script> tags at the bottom of your <body>, because this ensures the parser isn't blocked until the very end.

This approach has its own problem: the browser cannot start downloading the scripts until the entire document is parsed. For larger websites with large scripts & stylesheets, being able to download the script as soon as possible is very important for performance. If your website doesn't load within 2 seconds, people will go to another website.

In an optimal solution, the browser would start downloading your scripts as soon as possible, while at the same time parsing the rest of your document.

The modern approach

Today, browsers support the async and defer attributes on scripts. These attributes tell the browser it's safe to continue parsing while the scripts are being downloaded.

async

<script type="text/javascript" src="path/to/script1.js" async></script>
<script type="text/javascript" src="path/to/script2.js" async></script>
Scripts with the async attribute are executed asynchronously. This means the script is executed as soon as it's downloaded, without blocking the browser in the meantime.
This implies that it's possible script 2 is downloaded & executed before script 1.

<script type="text/javascript" src="path/to/script1.js" defer></script>
<script type="text/javascript" src="path/to/script2.js" defer></script>
Scripts with the defer attribute are executed in order (i.e. first script 1, then script 2). Like the async attribute, this does not block the browser.

Unlike async scripts, defer scripts are only executed after the entire document has been loaded.

This is contrary to what was stated in the comment above:
The good thing is that your website should still load correctly on the 20% of browsers that do not support these attributes, while speeding up the other 80%.

I don't know if it's a good idea or even possible/effective to run a quick browser compatibility check with something like Modernizr before loading the rest of the page (a script at the beginning of the page that executes before even rendering the DOM from the HTML file) and then dynamically add the defer/async attributes to the other script tags if the browser supports it.

I suppose the best solution is to have all your JavaScript files compiled to one compressed file and have that loaded with the defer/async attribute? Ideas/tips/remarks Dave McFarland ?

Thx!

sngliwei

16,105 Points

sngliwei

sngliwei

16,105 Points

June 11, 2015 6:26am

Awesome answer, thank you.

There are words missing in your sentence "The old approach to solve this problem was to put tags at the bottom of your , because this ensures the parser isn't blocked until the very end." - I think it should be "your HTML file"

Posting to the forum is only allowed for members with active accounts.
Please sign in or sign up to post.