The Importance of Script Tag Placement
Traditionally, script tags were positioned within the
<head> section of an HTML document. However, this placement was not without its drawbacks. The browser would halt the parsing of the HTML document to fetch and execute the script. This pause could lead to a noticeable delay in the loading of the webpage, negatively impacting the user experience.
To counteract this issue, developers started placing scripts at the bottom of the page, just before the closing
</body> tag. This allowed the HTML document to be fully parsed and the webpage to load before the script was executed. Although this mitigated the issue of page loading delays, it was not a foolproof solution. The execution of scripts could still potentially block the rendering of the webpage, and the order of script execution was not guaranteed.
Enter async and defer
To address these challenges, the
defer attributes were introduced. These boolean attributes, which can be added to the script tag, allow scripts to be fetched asynchronously, further enhancing the loading performance of webpages.
async attribute allows the script to be fetched in the background while the HTML document continues to be parsed. However, once the script is ready, the HTML parsing is paused, and the script is executed. This means that the execution order of multiple scripts with the
async attribute is not guaranteed — they will be executed in the order they are fetched and ready, which might not be the same as the order in the HTML document.
Here's an example of how the
async attribute is used:
<script async src="example-script.js"></script>
On the other hand, the
defer attribute also allows the script to be fetched in the background, but unlike
async, the script execution is deferred until the HTML document has been fully parsed. This ensures that scripts are executed in the order they appear in the HTML document.
Here's an example of how the
defer attribute is used:
<script defer src="example-script.js"></script>
async vs defer: A Performance Comparison
defer, placing a script in the
<head> of the document pauses the parsing of the HTML document until the script is fetched and executed. This can lead to longer page loading times, especially for larger scripts or slower network connections.
If the script is placed at the end of the
<body> tag without
defer, the HTML document parsing finishes before the script is fetched and executed. This can improve page loading time but might delay the script execution, which could be a problem if the script is critical for the webpage.
When using the
async attribute in the head, the script is fetched asynchronously, and the HTML parsing is only paused when the script is ready to be executed. This can lead to faster page loading times, but the execution order of scripts is not guaranteed.
defer attribute is used in the head, the script is fetched asynchronously, and the execution is deferred until the HTML parsing is complete. This guarantees the execution order of scripts and allows the browser to continue parsing the HTML document while the script is being fetched, leading to potentially faster page loading times.
Blocking Parsing and Rendering
It's important to note that the
async attribute blocks HTML parsing while the script is being executed. In contrast, the
defer attribute does not block HTML parsing, leading to potentially faster page loading times. Neither
defer make guarantees about blocking rendering — this largely depends on the implementation of the script itself.
domInteractive and Execution Order
Scripts with the
defer attribute are executed after the
domInteractive event. This event is triggered after the HTML document is loaded and parsed, and the Document Object Model (DOM) is built. In contrast, scripts with the
async attribute are executed as soon as they are ready, potentially before the
domInteractive event. This means that scripts with the
async attribute can be executed out of order, while scripts with the
defer attribute maintain their relative order as defined in the HTML document.
Best Practices for Using async and defer
To optimize page loading performance, it's generally recommended to place scripts in the
<head> of the document and add the
defer attribute to the script tag. This allows the script to be fetched asynchronously while the HTML document is being parsed, and the script execution is deferred until after the parsing is complete. This approach triggers the
domInteractive event earlier, improving the perceived page loading speed.
However, there might be cases where the
async attribute is more suitable. If a script is independent, meaning it doesn't rely on any other scripts, and the order of execution does not matter, the
async attribute might be a better choice. This allows the script to be executed as soon as it's ready, potentially speeding up the time until the script is run.
Here's a best practice example of how to use
<head> <script defer src="script1.js"></script> <script defer src="script2.js"></script> </head>
In this example, both scripts are fetched asynchronously while the HTML document is being parsed. The scripts are executed after the HTML parsing is complete, in the order they appear in the document. This ensures that
script1.js is executed before
script2.js, even if
script2.js finishes fetching first.
By understanding the differences between
defer script tags, developers can make informed decisions about which attribute to use to optimize script loading and execution, enhancing the user experience and improving the performance of their webpages.