Photo by Eric Er on Unsplash

On this page

Browsers parse HTML top to bottom. A ordinary <script src="..."> without async, defer, or type="module" fetches the file, then runs it immediately, which pauses parsing until execution finishes. CSS can block rendering in similar ways. The sections below map those defaults to async, defer, and ES modules.

When is HTML rendering blocked?

On initial page load, a parser-blocking script stops further HTML processing until the file is downloaded and executed. Stylesheets can block rendering while they load.

<script src="file.js"></script>

normal_html_parsing-1024x224.png

Blocking is costly for two reasons: the user waits longer for visible content, and inline scripts that run early may call document.getElementById before later markup exists.

Async JS loading

Placing scripts at the end of <body> avoids some ordering problems. The async attribute goes further: the file downloads in parallel with parsing, but execution still interrupts parsing when the download completes.

<script src="file.js" async></script>

async_js_loading-1024x267.png

Scripts with async run in unpredictable order relative to one another. Use async for independent snippets (analytics, ads) where order does not matter.

Deferred JS loading

defer also downloads in parallel with parsing, but the browser runs deferred classic scripts only after the document is parsed, in document order.

<script src="file.js" defer></script>

deferred_js_loading-1024x258.png

Multiple deferred scripts run in the order they appear in the HTML. That makes defer the usual choice for application bundles that depend on each other.

Module scripts

ES module scripts default to defer-like behavior: they fetch in parallel, run after parsing, and preserve order among module scripts. They also run in strict mode and use import/export.

<script type="module" src="app.js"></script>
<script nomodule src="legacy.js"></script>

import() inside a module still loads asynchronously at the call site. For how modules resolve, see A quick introduction to modules.

HTTP/2 and many small files

With HTTP/2, many parallel downloads are cheaper than they were on HTTP/1.1, but each classic script still pays a parse-and-run cost. Bundling and defer or type="module" remain relevant; multiplexing does not remove execution order concerns.

http_2_mulitplexing-1024x499.png

Use async when execution order does not matter. Use defer or type="module" when scripts must run after the DOM is parsed and, for classic scripts, in source order.

Search articles

Type a word to search published articles.

Open the search page