Script Loading
Overview
By default, when the browser encounters a <script> tag, it completely stops parsing HTML, downloads the JavaScript file, executes it, and only then resumes rendering the page. This is called 'render-blocking', and it destroys performance. Modern HTML5 introduces the defer and async attributes. They allow scripts to download silently in the background while the HTML continues to parse, ensuring the user sees the visual website instantly.
Syntax
<!-- 1. The Old Way (Render-Blocking) -->
<!-- Pauses the entire page until download and execution finish -->
<script src="analytics.js"></script>
<!-- 2. Async (Independent Execution) -->
<!-- Downloads in background, executes the EXACT second it finishes downloading -->
<!-- Used for independent scripts like Google Analytics -->
<script async src="analytics.js"></script>
<!-- 3. Defer (The Modern Standard) -->
<!-- Downloads in background, but waits to execute until the ENTIRE HTML DOM is fully built -->
<!-- Used for main application logic (React/Vue/Vanilla JS) -->
<script defer src="app.js"></script>Common Pitfalls
- Using
asyncon scripts that depend on each other. Becauseasyncscripts execute immediately upon downloading, a small script might execute before the massive library it relies on (like React) finishes downloading, causing a fatal ReferenceError. - Placing
<script defer>at the very bottom of the<body>. The whole point ofdeferis that it allows the script to download in the background while the HTML parses. If you put it at the bottom, the download doesn't start until the HTML is already finished, wasting precious time. Put<script defer>in the<head>.
Interview Questions
async and defer?async executes scripts in random order based on whichever downloads fastest. defer respects the exact top-to-bottom order you wrote them in the HTML, and only executes after the DOM tree is complete.
Real-World Example
A heavily optimized Next.js/React document head loading third-party trackers and core logic.
<head>
<!-- Independent tracker: We don't care when it executes, just do it fast -->
<script async src="https://www.googletagmanager.com/gtag/js?id=123"></script>
<!-- Core app logic: Download in background, but WAIT to execute until the DOM is ready -->
<script defer src="/static/js/bundle.js"></script>
</head>Check Your Knowledge
Test your understanding of Script Loading with these quick questions.