defer と async は、外部の <script> がHTMLの解析に対していつダウンロードして実行されるかを変更します。どちらもスクリプトを並列にダウンロードでき、パーサーをブロックしません。違いは実行のタイミングです。
html
<script src="a.js"></script> <!-- blocks parsing: download + run, THEN continue -->
<script src="a.js" defer></script> <!-- parse continues; run after DOM, IN ORDER -->
<script src="a.js" async></script> <!-- parse continues; run ASAP, ANY order -->
ビジュアルタイムライン
text
Normal: parse──stop──[download+exec]──parse──────── (slowest)
async: parse──────────────────exec──parse──────── (runs whenever it arrives)
defer: parse───────────────────────────parse──exec (after parsing, before DOMContentLoaded)
主な違い
async | defer | |
|---|---|---|
| ダウンロード | 並列 | 並列 |
| 実行 | ダウンロード完了直後 | HTML完全解析後 |
| 順序は保証される? | いいえ (先に終わった方) | はい (ドキュメント順) |
| パーサーをブロック? | 実行中のみ短時間 | しない |
どちらを使うか
defer— DOMに触れたり、相互に依存する/順序に依存するスクリプト向け(アプリコード)。DOMが存在してから順序通り実行され、DOMContentLoadedの直前に実行されます。async— 独立したサードパーティスクリプト(アナリティクス、広告など)で、DOMや他のスクリプトに依存しないもの向け。順序は関係なく、できるだけ早く実行します。
html
<script src="analytics.js" async></script> <!-- independent → async -->
<script src="app.js" defer></script> <!-- app logic, ordered → defer -->
注: どちらも 外部 スクリプト (src) にのみ適用されます。インラインスクリプトでは無視されます。ESモジュール (type="module") はデフォルトで遅延実行されます。
なぜ重要なのか
defer/async を使うことで、スクリプトがHTMLの解析をブロックするのを防ぎ、読み込みパフォーマンスと First Contentful Paint を直接向上させます。
正しい方を選ぶこと(defer は順序が重要でDOM依存のアプリコード用、async はファイアアンドフォーゲットなサードパーティスクリプト用)は、遅い読み込みと順序依存バグの両方を避けられます。
