Mastering Script Loading for Optimal Web Performance (Async and Defer) Interview Special
Introduction
In the world of web development, optimizing script loading is crucial for ensuring efficient web performance. The speed at which web pages load not only affects SEO rankings but also significantly impacts user experience and satisfaction. This article explores the techniques for loading scripts efficiently, with a special focus on the async
and defer
attributes.
The Importance of Web Page Loading
The loading speed of a web page is a critical factor that can influence SEO rankings, user experience, and overall user satisfaction. Achieving a fast first paint
is essential in today's digital landscape. JavaScript, as a fundamental part of web applications, must be managed carefully during loading and execution to ensure optimal performance. JavaScript is often referred to as a "parser-blocking resource" because it can obstruct the parsing of the HTML document itself.
<!DOCTYPE html>
<html>
<head>
<title>Script Loading Example</title>
</head>
<body>
<p>...content before script...</p>
<!-- A heavy script blocking the page -->
<script src="heavy-script.js"></script>
<!-- Content below the script -->
<p>...content after script...</p>
</body>
</html>
When a web page loads, it follows a sequence of events:
HTML Parsing
HTML Parsing Paused
Script Download
Script Execution
Loading script in the head
Traditionally, web developers were taught to include external scripts within the head element of the HTML. However, this approach has its limitations, especially when dealing with slow network connections or mobile devices, where the page may remain blank while waiting for a script to load and execute.
Moving Scripts to the Bottom
To address this issue, it's often recommended to place script tags at the bottom of the body element. This allows the DOM to be rendered before the script is loaded, leading to a better user experience. Nevertheless, this solution isn't perfect, especially for lengthy HTML documents, as there may still be noticeable delays.
<!DOCTYPE html>
<html>
<head>
<title>Script Loading Example</title>
</head>
<body>
<p>...all content is above the script...</p>
<!-- Placing the script at the bottom -->
<script src="script.js"></script>
</body>
</html>
Leveraging HTML5 Attributes: Async and Defer
HTML5 introduced two attributes for the script tag: async
and defer
These attributes can significantly impact how scripts are loaded and executed.
Loading Scripts Without Any Attributes
When loading a script without any attributes, the parsing of the DOM is paused when the script tag is encountered, and it only resumes parsing after the script has been downloaded and executed.
<!DOCTYPE html>
<html>
<head>
<title>Script Loading Example</title>
</head>
<body>
<p>...content before script...</p>
<!-- A script without attributes -->
<script src="script.js"></script>
<p>...content after script...</p>
</body>
</html>
Loading Scripts with "Async"
Using the async
attribute allows the script to be downloaded while the DOM is parsing, pausing the DOM only during the script's execution. "Async" scripts follow a "load-first" order, which means that a smaller script may load and execute before a larger one.
It's worth noting that async
is not recommended when there is a dependency on other scripts, as the order of execution is not guaranteed.
<!DOCTYPE html>
<html>
<head>
<title>Script Loading Example</title>
</head>
<body>
<p>...content before script...</p>
<!-- Using "async" attribute -->
<script async src="script.js"></script>
<p>...content after script...</p>
</body>
</html>
Loading Scripts with "Defer"
On the other hand, the defer
attribute downloads the script while the DOM is still parsing but executes it only after the parsing is completed. Defer
is equivalent to loading the script at the end of the body tag.
Deferred scripts are executed in the order they are placed, and they execute after the domInteractive event, which occurs when the HTML is loaded and executed, and the DOM is built.
<!DOCTYPE html>
<html>
<head>
<title>Script Loading Example</title>
</head>
<body>
<p>...content before script...</p>
<!-- Using "defer" attribute -->
<script defer src="script.js"></script>
<p>...content after script...</p>
</body>
</html>
Choosing the Best Approach: Async or Defer?
When deciding between async
and defer,
consider the following:
If a script is not dependent on any other script and the order of execution doesn't matter,
async
is a good choice.If a script depends on another script or the DOM, "defer" is the better option.
For small scripts that are relied upon by an
async
script, consider using an inline script with no attributes placed above the "async" scripts.
In conclusion, mastering the art of script loading is crucial for optimizing web performance. By carefully selecting the appropriate loading technique, whether async
or defer,
web developers can significantly enhance the user experience and meet the demands of today's digital landscape.
A Deep Dive into Async and Defer
In the context of web development, scripts play a significant role in shaping the performance and user experience of modern websites. The download size of scripts is often larger than HTML, and their processing time can be substantial. When a web page is loaded, and the browser encounters a <script>
tag, whether inline or external, it can't continue building the DOM until the script is executed. This can lead to two critical issues:
Scripts Can't Interact with DOM Elements Below: Scripts that are higher in the page's HTML structure can't interact with DOM elements below them. This limitation prevents them from adding event handlers or making changes to elements further down the page.
Blocking Page Loading: If a heavy script is placed at the top of the page, it essentially "blocks" the page. Users can't see any page content until this script is downloaded and executed, which can result in a less-than-ideal user experience.
One workaround for the second issue is to place the script at the bottom of the page. This allows the DOM to be constructed before the script is loaded, improving user experience. However, this approach has its drawbacks, particularly in cases of lengthy HTML documents where the delay in script loading can still be noticeable.
Introducing Defer and Async Attributes
To address these script loading challenges, HTML5 introduced two attributes for the <script>
tag: defer
and async
. Let's explore how they work:
Defer Attribute
The defer
attribute instructs the browser not to wait for the script. Instead, it continues processing the HTML, building the DOM in the background. The script loads concurrently and only runs once the DOM is fully constructed. In summary, scripts with defer
attribute:
Don't block the page rendering.
Execute when the DOM is ready (but before the DOMContentLoaded event). The "defer" attribute is particularly useful when a script depends on the complete DOM structure.
Async Attribute
async
downloads the script while the DOM is parsing and only pauses the DOM for execution of the script.
Async scripts follow load-first
order. Which means if a second script of suppose 5kb loads before first script of 10kb then the second will execute first.
That is why we should not use async when there is dependency on other script like `Jquery`.
The DOMContentLoaded
event may fire before and after an async script is loaded. There is no guarantee.
If you cant understand it just read last para of async
The async
attribute is similar to defer
in that it makes the script non-blocking. However, it differs in some key ways:
The browser doesn't wait for
async
scripts, similar todefer
.Other scripts, whether "async" or not, don't wait for "async" scripts, and vice versa.
DOMContentLoaded and
async
scripts are independent of each other, so they may execute in any order.
In other words, async
scripts load in the background and run when ready, without waiting for anything. They are fully independent scripts. This attribute is ideal for integrating independent third-party scripts like analytics or ads.
Dynamic Scripts
Another method for adding scripts to a page is by dynamically creating a script element using JavaScript. When dynamically appended to the document, these scripts behave as if they have the async
attribute enabled, which means they don't wait for anything and execute independently.
However, you can change this behavior by explicitly setting script.async = false
, which makes the scripts execute in the order they were added to the document, much like defer.
Summary
In summary, both async
and defer
attributes allow scripts to load without blocking page rendering. Users can start interacting with the page content without waiting for scripts to complete their execution. However, there are essential differences between them:
Async
scripts are load-first order and fully independent.Defer
scripts execute in the order they appear in the document and wait for the DOM to be fully loaded.
Choosing between async
and defer
depends on your script's dependencies and the desired execution order. Async
is suitable for independent scripts, while defer
is ideal when scripts rely on the complete DOM.
Regardless of your choice, it's crucial