JavaScriptファイルをHTMLファイルのどこで読み込むのか?
<body>要素の末尾? <head>要素の中? 属性は?
JavaScriptファイルの読み込み位置ごとに、注意点やメリット/デメリットを解説します。
JavaScript入門者向けのテキストやネット記事をいくつか拝見して、方法が1つしか紹介されていないケースを散見したので記事にしました。
結論
JavaScriptファイルの読み込み位置は、実行順やDOM操作の有無を考慮して使い分ける。
-
<head>
内に<script src="..." defer>
で書く- スクリプトの順序が重要
- DOM操作がある
-
<body>
要素の末尾(</body>の直前) に書く- DOM操作がある
- 画面描写速度重視(bodyを先に読み込む)
- 伝統的な書き方を継承
-
<head>
内に<script src="..." async>
で書く- 非同期実行(DOM依存がない、単体で完結する)
モダンな構成では「 <head>
タグ内に直接書く(defer属性 async属性を付けない)」ケースはあまりない。
しかし、 後続のスクリプト(他のJSファイルやBody)よりも、確実に先に実行しておきたい場合に使用する事もある。
JavaScriptファイルの読み込み位置は主に4パターン
-
<head>
タグ内に直接書く(defer属性 async属性を付けない) -
<head>
内に<script src="..." defer>
で書く -
<head>
内に<script src="..." async>
で書く -
<body>
要素の末尾(</body>の直前) に書く
それぞれの特徴を見ていきましょう。
1. <head>
タグ内に直接書く(同期読み込み)
<head>
<title>ページタイトル</title>
<script src="script.js"></script>
</head>
メリット
- HTMLを読み込む前にJavaScriptが実行されるため、初期化が早い。
デメリット
- モダンな構成ではあまりない。
しかし、 後続のスクリプト(他のJSファイルやBody)よりも、確実に先に実行しておきたい場合使用する事もある - JavaScriptの読み込み・実行が終わるまで、HTMLの解析が止まる(レンダリングがブロックされる)。
- 上記により、画面描画速度が遅くなる可能性がある。
注意
- DOM操作できない。
コードは上からレンダリングされるため、そもそもJavaScriptでDOM操作する対象(body内の要素)がレンダリングされていないためエラーとなります。 - 上記の対策にJavaScriptコード内で、「addEventListener(loadイベント、DOMContentLoadedイベント)」を使ってレンダリング終了後に、DOM操作を実行する方法もありましたが、次に紹介する方法が主流になっています。
2. <head>
内に<script src="..." defer>
で書く(非同期+順序維持)
<head>
<title>ページタイトル</title>
<script src="script.js" defer></script>
</head>
メリット
- HTMLの解析と並行してスクリプトを読み込む。
- HTMLのパース完了後にスクリプトが実行される。
- 複数スクリプトでも記述順通りに実行される。
デメリット
- IEなどの古いブラウザでは非対応の場合がある(※現在ではあまり問題なし)
3. <head>
内に<script src="..." async>
で書く(非同期+即時実行)
<head>
<title>ページタイトル</title>
<script src="script.js" async></script>
</head>
メリット
- HTMLの解析と並行してスクリプトを読み込み、読み込み完了後すぐに実行される。
- 最速でスクリプトを実行できる可能性がある。
デメリット
- 実行順が保証されないため、複数のスクリプトがあると依存関係が崩れる恐れがある。
- IEなどの古いブラウザでは非対応の場合がある(※現在ではあまり問題なし)
4. <body>
要素の末尾(</body>の直前) に書く
<body>
<!-- コンテンツ -->
...
...
...
<script src="script.js"></script>
</body>
メリット
- HTMLのパースが終わってからスクリプトが実行されるため、レンダリングがブロックされない。
- 古くからある手法で、互換性が非常に高い。
デメリット
-
<head>
に比べてHTMLが長くなり、管理が煩雑になりやすい。 - 大規模なプロジェクトでは可読性に注意。
おまけ:deferとasyncの違いを図で確認
属性 | 読み込み | 実行タイミング | 実行順序 |
---|---|---|---|
なし | 同期 | 読み込み時(すぐ) | 順序通り |
defer | 非同期 | HTML解析後(DOMContentLoaded前) | 順序通り |
async | 非同期 | 読み込み完了時(すぐ) | 順序保証なし |