Efficiently load JavaScript with defer and async
When loading a script on an HTML page, it’s important to consider its impact on the loading performance. The position and method of adding scripts to an HTML page can greatly influence the loading time.
Traditionally, scripts are included in the page using the following syntax:
1 | <script src="script.js"></script> |
When the HTML parser encounters this line, it fetches the script and executes it. This process introduces delay, which can negatively affect the loading time of the page. If the script takes longer to load than expected, the visitor may see a blank page until the script is loaded and executed.
The position of the script tag also matters. Initially, script tags are often placed in the <head>
tag:
1 | <html> |
In this scenario, the parser fetches and executes the script before continuing to parse the body. This delay can be significant. To improve loading performance, it is common practice to place the script tag at the bottom of the page, just before the closing </body>
tag. This allows the script to load and execute after the rest of the page is parsed and loaded, resulting in a significant improvement.
For older browsers that don’t support the newer HTML features async
and defer
, this is the best approach. However, for modern browsers, the async
and defer
attributes can be utilized.
Both async
and defer
are boolean attributes and can be used as follows:
1 | <script async src="script.js"></script> |
1 | <script defer src="script.js"></script> |
If both attributes are specified, async
takes precedence in modern browsers, while older browsers that support defer
but not async
will fallback to using defer
.
It’s important to note that these attributes are only effective when used in the head
portion of the page and are unnecessary if the script is placed at the end of the body
tag.
To showcase the performance differences, let’s compare different scenarios:
- No
defer
orasync
, script in thehead
- No
defer
orasync
, script in thebody
async
script in thehead
defer
script in thehead
In the first scenario, without defer
or async
, the parsing is paused until the script is fetched and executed. Only then does the parsing resume.
In the second scenario, without defer
or async
, the script in the body
does not interrupt the parsing. Instead, parsing continues, and the script is fetched and executed after parsing is complete. This allows the page to appear to the user faster compared to the first scenario.
In the third scenario, with async
in the head
, the script is fetched asynchronously. Once it’s ready, the HTML parsing is paused to execute the script, and then it resumes.
In the fourth scenario, with defer
in the head
, the script is fetched asynchronously and executed only after the HTML parsing is done. This approach is similar to placing the script at the end of the body
tag. However, the script execution finishes earlier because it can be downloaded in parallel with the HTML parsing. This is the fastest approach.
Using async
blocks the parsing of the page, while defer
does not. Neither async
nor defer
explicitly guarantee non-blocking rendering. It is up to the developer to ensure proper rendering, such as waiting for the onLoad
event.
Scripts marked with defer
are executed right after the domInteractive
event, which occurs after the HTML is loaded, parsed, and the DOM is built. CSS and images are still being parsed and loaded at this point. Afterward, the browser emits the domComplete
event, followed by onLoad
. The timing of the domInteractive
event is considered a measure of perceived loading speed.
When it comes to ordering, scripts marked with async
are executed in casual order as they become available. In contrast, scripts marked with defer
are executed in the order in which they are defined in the markup.
To achieve the best loading performance with scripts, it is recommended to place them in the head
section of the page and add the defer
attribute to the script
tag:
1 | <script defer src="script.js"></script> |
This approach triggers the faster domInteractive
event. Considering the advantages of defer
, it is often a better choice than async
in various scenarios. Unless delaying the first render of the page is acceptable, ensure that the necessary JavaScript is executed once the page is parsed.