LESSON 05 · BEGINNER4 min read

Script Loading Strategies: Synchronous, Async, Defer, and ES Modules

Master modern script loading mechanics: parser-blocking scripts, asynchronous execution (async), deferred execution (defer), and native ES Modules (type='module').

HTML5 / Living StandardFree to readModule 1 of 8
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Analyze why default synchronous <script> tags block the HTML tokenizer and stall DOM construction
  • Contrast async (executes immediately upon download) with defer (executes in DOM order at DOMContentLoaded)
  • Implement native ES Modules (<script type='module'>) and explain deferred execution by default

01The Problem of Parser-Blocking Synchronous Scripts

By default, when the browser's HTML parser encounters a standard <script src="app.js"></script> tag, parsing of the HTML document halts completely. The browser must pause the HTML tokenizer, make a network request to download the script file, execute the script immediately, and only then resume HTML parsing.

Why must browsers block by default? Because synchronous JavaScript is permitted to call document.write("<p>Dynamic content</p>"), which directly injects raw markup into the parser's input byte stream! The parser cannot safely continue parsing until it knows whether JavaScript will mutate the stream.

In modern web applications, synchronous scripts located in the <head> create a massive performance bottleneck, stalling First Contentful Paint by several seconds on high-latency mobile networks.

index.htmlHTML
<!-- 1. Parser-Blocking: Stalls HTML parsing until downloaded & executed --><script src="legacy.js"></script><!-- 2. Async: Downloads in background, executes IMMEDIATELY upon arrival (Interrupts parser!) --><script async src="analytics.js"></script><!-- 3. Defer: Downloads in background, executes in ORDER when DOM is parsed (Best for apps!) --><script defer src="application.js"></script><!-- 4. Module: Native ES Module (Deferred by default, strict mode, scoped) --><script type="module" src="main.js"></script>

02Async vs Defer: The Crucial Execution Timing Difference

Both async and defer download external JavaScript files asynchronously in background threads without blocking HTML tokenization. However, their execution timings are radically different:

async (<script async>): Executes the instant the script finishes downloading over the network. When execution begins, HTML parsing PAUSES. If two async scripts are declared (a.js and b.js), there is NO guaranteed execution order—whichever script downloads first executes first! Use async strictly for independent third-party utilities (Google Analytics, ad trackers).

defer (<script defer>): Downloads in the background, but pauses execution until the ENTIRE HTML document has been parsed into the DOM tree. Crucially, deferred scripts preserve document order: script 1 is guaranteed to execute before script 2. Execution finishes right before the DOMContentLoaded event fires. Ideal for application business logic.

03Native ES Modules: type='module'

Modern web development standardizes on native ES Modules via <script type="module" src="main.js"></script>.

ES Modules provide four major advantages: 1. Deferred by default: Modules execute automatically with defer behavior without needing an explicit defer attribute.

2. Scoped execution: Variables declared at top-level do not pollute the global window object. 3. Strict mode: Executed in JavaScript strict mode ('use strict') automatically. 4. Native imports: Supports standard import / export syntax across modular file trees.

04Script Loading Timeline Comparison

Visualizing parser execution during script downloads:

Use defer or type="module" for your application code; use async strictly for independent analytics trackers.

notes.txtPlain text
HTML Parsing:   [==== PARSE ====] -------- PAUSE -------- [==== PARSE ====]Sync Script:                     [ FETCH ] [ EXECUTE ]HTML Parsing:   [=============== PARSE ===============] -- PAUSE -- [==== PARSE ====]Async Script:   [ FETCHING IN BACKGROUND ]             [ EXECUTE ]HTML Parsing:   [======================== COMPLETE PARSE ========================]Defer Script:   [ FETCHING IN BACKGROUND ]                                       [ EXECUTE ]Event:                                                                           DOMContentLoaded

05Production Standards & Real-World Engineering Trade-Offs

From a browser engine rendering perspective, understanding how the HTML parser interacts with the critical rendering path is essential for front-end performance engineering. As the browser streams bytes from the network, it passes them through tokenization, tree construction, and layout phases. If external stylesheet links or blocking synchronous scripts interrupt the HTML tokenizer, the browser cannot proceed with layout or paint, resulting in white-screen delays that directly impair user conversion rates.

Furthermore, modern browser engines (Blink, Gecko, WebKit) enforce strict speculation rules. Preload scanners parse ahead in raw HTML byte streams to discover and fetch high-priority subresources—such as hero fonts, responsive images, and critical style sheets—long before the main DOM tree construction reaches those elements, cutting First Contentful Paint (FCP) times dramatically.

LET IT CLICK

The ideas worth keeping.

  • Synchronous scripts block HTML parsing; avoid placing raw <script> in document <head>.
  • Use defer for application scripts to ensure execution occurs in order after DOM parsing.
  • Use async exclusively for independent third-party trackers with no code dependencies.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Edit the starter, press Preview, and see your page render in the browser preview. Compare with the worked solution when ready.

01

Exercise 1: Given two scripts app js and lib js where app

Given two scripts app.js and lib.js where app.js depends on functions inside lib.js, explain why <script async src="lib.js"></script> and <script async src="app.js"></script> will fail intermittently.

your_turn_1.html🌐HTML
Ctrl + ↵
Preview
Press Preview to render your page
Press Preview to render your HTML in the browser preview.
Explore a worked solution
one_possible_solution.htmlHTML
// The async attribute executes each script immediately upon network download completion.// If app.js (10KB) finishes downloading before lib.js (150KB), app.js will execute first.// When app.js calls functions defined in lib.js, a ReferenceError occurs because lib.js// has not yet downloaded or executed.// Fix: Use 'defer' instead of 'async' to guarantee scripts execute in exact document order.

Does async guarantee execution order between multiple files?

02

Exercise 2: What are two default behaviors of script typ

What are two default behaviors of <script type="module"> that differ from standard <script> tags?

your_turn_2.html🌐HTML
Ctrl + ↵
Preview
Press Preview to render your page
Press Preview to render your HTML in the browser preview.
Explore a worked solution
one_possible_solution.htmlHTML
// 1. ES Modules are deferred by default (they execute after the HTML document is fully parsed).// 2. ES Modules execute in strict mode ('use strict') and have their own module scope//    (top-level variables do not pollute the global window object).

Think about execution timing and variable scope.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01Why do standard synchronous <script> tags block the HTML parser?
02When does a <script defer> tag execute?
03When is the async attribute (<script async>) appropriate?

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

MODULE 01 · PRACTICAL SELF-CHECK

Pause. Put the pieces together.

You’ve reached the end of HTML Foundations: Your First Page, Document Anatomy & Browser Parsing. Before moving on, use this task to check what you can do independently.

Build a valid HTML5 page with UTF-8, a responsive viewport, and a deferred script that passes W3C validation.

Try it in your own environment and write down the result. This is a self-check; reading completion does not evaluate your code.

Review this module

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Completion is saved in this browser. It records reading and hands-on practice progress.