Webサイトのフロントエンド開発において、JavaScriptの読み込み最適化は避けて通れない重要なテーマです。
特に、HTMLの解析(パース)を妨げずにスクリプトを実行するためのdefer属性とasync属性の使い分けは、ページの表示速度やユーザー体験に直結します。
2026年のWeb開発シーンにおいても、これらの属性を正しく理解し、ブラウザのレンダリングプロセスに最適化させる技術は、エンジニアにとって必須のスキルといえるでしょう。
JavaScriptの読み込みがパフォーマンスに与える影響
現代のWebサイトは、かつてないほど多くのJavaScriptに依存しています。
しかし、ブラウザがHTMLを解析している最中に通常の<script>タグに遭遇すると、そのスクリプトのダウンロードと実行が完了するまでHTMLの解析が一時停止してしまいます。
これを「パースブロッキング」と呼びます。
パースブロッキングが発生すると、ユーザーの画面には何も表示されない、あるいは中途半端なレイアウトのままフリーズしたような状態が続きます。
これは、コアウェブバイタル(Core Web Vitals)などの指標、特にLCP(Largest Contentful Paint)や、2024年以降重要視されているINP(Interaction to Next Paint)に悪影響を及ぼします。
こうした問題を回避し、効率的にスクリプトを読み込むために導入されたのが、asyncとdeferという2つの属性です。
通常のスクリプト読み込みの挙動
まずは比較の基準となる、属性を指定しない場合の挙動を整理しましょう。
<!-- 通常のスクリプト読み込み -->
<script src="main.js"></script>
通常の<script>タグが記述されている場合、ブラウザはHTMLを上から順に読み込み、タグを見つけた時点でHTMLのパースを中断します。
その後、ネットワークを通じてスクリプトファイルをダウンロードし、実行を終えてからようやくHTMLのパースを再開します。
この挙動の問題点は、スクリプトのファイルサイズが大きかったり、ネットワーク接続が低速だったりする場合、HTMLの後半部分(例えばフッターやコンテンツの下部)のレンダリングが大幅に遅れることです。
これを避けるために、古くは</body>タグの直前にスクリプトを記述する手法が一般的でしたが、現在ではより制御しやすい属性の利用が推奨されています。
async属性の特徴と実行タイミング
asyncは「asynchronous(非同期)」の略で、その名の通りスクリプトを非同期で読み込むための属性です。
<!-- async属性を使用した読み込み -->
<script async src="analytics.js"></script>
asyncの挙動
asyncを指定すると、ブラウザはHTMLのパースを継続しながら、並行してスクリプトのダウンロードを開始します。
ここまでは効率的ですが、注意が必要なのは実行タイミングです。
スクリプトのダウンロードが完了した瞬間に、HTMLのパースを中断して実行が始まります。
つまり、ダウンロードが終わるタイミング次第では、HTMLのパースが完了していない状態で実行される可能性があります。
また、複数のasyncスクリプトがある場合、記述順に関係なく「早くダウンロードが終わった順」に実行されるという特徴があります。
asyncの主な用途
asyncは、そのスクリプトが他のスクリプトに依存せず、かつDOMの構築完了を待つ必要がない場合に適しています。
- アクセス解析ツール(Google Analyticsなど)
- 広告配信スクリプト
- ページ上の特定の機能に影響を与えない独立したウィジェット
これらのスクリプトは、実行の順番が前後しても問題がなく、またページのメインコンテンツの表示を邪魔したくないため、asyncが最適です。
defer属性の特徴と実行タイミング
一方、deferは「遅延」を意味し、HTMLのパースが終わるまで実行を後回しにする属性です。
<!-- defer属性を使用した読み込み -->
<script defer src="app.js"></script>
deferの挙動
deferを指定した場合も、asyncと同様にHTMLのパースと並行してスクリプトのダウンロードが行われます。
しかし、asyncと決定的に違うのは、HTMLのパースがすべて完了してから実行されるという点です。
具体的には、ブラウザがHTMLを最後まで読み込み、DOMの構築が終わった後に発生するDOMContentLoadedイベントの直前に実行されます。
また、複数のスクリプトにdeferが付与されている場合、記述された順番通りに実行されることが保証されています。
deferの主な用途
deferは、現代のWebアプリケーションにおいて最も推奨される読み込み方式です。
- メインのアプリケーションロジック(UI操作やイベントリスナーの登録)
- DOM要素が生成されていることを前提としたスクリプト
- 実行順序が重要な複数のライブラリ(jQueryプラグインなど)
DOMツリーが完成した状態で実行されるため、スクリプト内でdocument.getElementById()などを使って要素を操作する際も、エラーが発生する心配がありません。
読み込み順序と実行タイミングの比較表
各属性の挙動の違いを明確にするために、以下の表にまとめました。
| 属性 | HTMLパースとの関係 | 実行タイミング | 実行順序の保証 |
|---|---|---|---|
| なし | パースを中断してダウンロード・実行 | 即時(パースを止める) | 記述順 |
async | パースと並行してダウンロード | ダウンロード完了後すぐ | 順不同 |
defer | パースと並行してダウンロード | パース完了後 | 記述順通り |
この表からわかる通り、deferはパフォーマンスの向上と実行の安定性を両立させた、非常にバランスの良い選択肢です。
実践的な使い分けの判断基準
開発者がどちらを選択すべきか迷った際の判断基準を、具体的なシナリオに基づいて解説します。
1. 依存関係がある場合
例えば、library.jsを読み込んだ後に、それを利用するmain.jsを実行したい場合、asyncを使うのは危険です。
main.jsのダウンロードが先に終わると、ライブラリが存在しない状態で実行され、エラーになります。
この場合は必ずdeferを選択してください。
<!-- 正しい順序で実行される -->
<script defer src="library.js"></script>
<script defer src="main.js"></script>
2. 実行速度を最優先する場合
とにかく1秒でも早くスクリプトを実行し、データの収集を開始したい計測タグなどはasyncが向いています。
ページの表示が完了するのを待つ必要がないため、バックグラウンドで処理を進めることができます。
3. モジュールシステム(type=”module”)の場合
2026年現在のモダンな開発では、<script type="module">を使用することが一般的です。
重要な点として、ESモジュール(type=”module”)はデフォルトでdeferと同じ挙動になります。
<!-- デフォルトでdeferと同じ挙動になる -->
<script type="module" src="app.js"></script>
<!-- 明示的にasyncを指定することも可能 -->
<script type="module" async src="analytics-module.js"></script>
モジュールを使用する場合、基本的には属性を意識しなくてもパースブロッキングは発生しませんが、特定の順序制御が必要な場合にはasyncを追加で指定することがあります。
パフォーマンス計測とブラウザの最適化
属性を使い分けるだけでなく、実際にどの程度の効果があるかを計測することも重要です。
Chromeのデベロッチャーツールの「Network」タブや「Performance」タブを使用すると、HTMLパースの進行状況とスクリプトの実行タイミングを可視化できます。
特にMain Thread(メインスレッド)の動きを注視してください。
長いタスク(Long Tasks)が発生している場合、それはスクリプトの実行タイミングや実行時間が適切でないサインです。
deferを活用して、ブラウザが最も忙しい「パースとレンダリングの初期段階」から実行をずらすことで、ユーザーの操作に対する応答性を高めることができます。
2026年のトレンド:Resource Hintsとの組み合わせ
現代のWeb開発では、deferやasyncに加えて、rel="preload"などのリソースヒントを組み合わせる手法が一般的です。
<!-- 重要なスクリプトを事前に読み込み指示 -->
<link rel="preload" href="critical-script.js" as="script">
<!-- その後、deferで実行 -->
<script defer src="critical-script.js"></script>
このように記述することで、ブラウザに対して「このスクリプトは後で使うので、今のうちにネットワークの空き帯域を使ってダウンロードしておいてほしい」と伝えることができます。
これにより、deferの弱点である「ダウンロード開始が遅れる可能性」を補い、パース完了後すぐに実行できる準備を整えることが可能です。
よくある間違いとトラブルシューティング
インラインスクリプトへの指定
deferやasyncは、src属性を持つ外部スクリプトに対してのみ有効です。
以下のようなインラインスクリプトに記述しても無視されるため注意が必要です。
// これは無視され、即時実行(パースブロッキング)される
<script defer>
console.log("This will execute immediately.");
</script>
ただし、前述のtype="module"を指定した場合は、インラインであっても非同期的に扱われます。
document.write() の使用
asyncやdeferを使用しているスクリプト内でdocument.write()を使用することは厳禁です。
これらの属性によって実行タイミングがずれるため、すでに閉じられたDOMに対して書き込みを行おうとして、ページの内容がすべて消去されるなどの致命的な不具合を招く可能性があります。
まとめ
JavaScriptの読み込み最適化において、deferとasyncの使い分けは、単なるテクニックではなく、Webパフォーマンスにおける基本戦略です。
- defer:HTMLパースを妨げず、DOM構築完了後に実行。依存関係がある場合や、UI操作を行うメインスクリプトに最適。
- async:HTMLパースを妨げず、ダウンロード完了次第すぐに実行。他と依存関係がない解析ツールや広告タグに最適。
- 通常スクリプト:パースを中断するため、現代のWeb開発では使用を避けるべき。
2026年のWeb開発では、ユーザーの待ち時間を最小限に抑えることがこれまで以上に求められています。
スクリプトの性質を正しく判断し、適切な属性を選択することで、より滑らかで高速なWebサイトを構築していきましょう。
また、ESモジュールの挙動やリソースヒント(preload等)との組み合わせも考慮に入れ、包括的なパフォーマンス最適化を心がけてください。
