Compare a plain <script>, one with defer, and one with async. When would you reach for each?
Understanding how each attribute changes download timing, execution timing, and order.
All three download the same file; they differ in WHEN download happens and WHEN execution happens relative to HTML parsing. A plain <script> is parser-blocking: the parser stops, downloads, executes, then resumes — so it delays DOM construction and first paint, and scripts run in document order. `defer` downloads the script in parallel while parsing continues, then executes it only AFTER the DOM is fully parsed (just before DOMContentLoaded), and deferred scripts run in order. This is the default choice for app code: it never blocks the parser and it can safely touch the DOM because parsing is done. `async` also downloads in parallel, but executes as soon as it arrives — which can be mid-parse — and async scripts run in no guaranteed order (whoever downloads first runs first). Use `async` for independent, order-insensitive scripts that don't touch your DOM: analytics, an ad tag, an isolated widget. Rule of thumb: reach for `defer` for anything that's part of your app or depends on the DOM or on other scripts; reach for `async` for fire-and-forget third parties; avoid plain synchronous scripts in <head> entirely. Note both attributes only apply to external scripts (with src); on an inline script they're ignored. Also: type=module scripts are deferred by default.
Deciding how to include any script; fixing a script that blocks paint or runs before the DOM exists.
<!-- Blocks parsing until downloaded + executed -->
<script src="a.js"></script>
<!-- Downloads in parallel, runs after DOM is parsed, in order. Default for app code. -->
<script src="framework.js" defer></script>
<script src="app.js" defer></script>
<!-- Downloads in parallel, runs ASAP, no order guarantee. For independent 3rd parties. -->
<script src="analytics.js" async></script>