JavaScriptファイルを読み込ませるときの順序で「サイトの読み込み速度に影響が出るので</body>
の直前に入れましょう」というのはずっと昔からのテクニックとして存在しています。現にそうしているサイトはたくさんありますが、「async
/defer
属性を付与して<head>
内で読み込ませる」とHTMLパース(解析処理)を妨げず、結果的にサイト読み込みの高速化に繋げることができます。本記事はJavaScriptファイルの読み込みタイミングについて書いています。
async/defer属性を知るために
async
/defer
属性に関わる「DOMContentLoaded
」、「load
」という2つのイベントがあります。イベントとはページの読み込みやボタンのクリックなど、ページで発生させるアクションのことです。
DOMContentLoaded
HTMLパースが完了した時点で発生するイベントです。
load
HTMLパースが完了し、CSSや画像などの読み込みが完了し、JavaScriptのダウンロード・実行など全ての処理が完了した時点で発生するイベントです。
ページの読み込みタイミング
実際どのように読み込まれているかイメージ図で表しました。
読み込みの違い
どちらの属性もつけない(デフォルトの)場合
コード
<script src="js/index.js"></script>
async
/defer
属性をつけない状態だと、HTMLパース中に<script>
タグにたどり着いたらHTMLパースは一時中断され、JSのダウンロードと実行をします。JSの実行が完了するとHTMLパースが再開されます。
async属性をつけた場合
コード
<script async src="js/index.js"></script>
HTMLパースは止まることなくJSのダウンロードが進みますが、ダウンロード完了直後にJSが実行され、実行中はHTMLパースが一時中断されます。<script>タグを複数記述した時の実行順序は<script>タグを記述した順番にはなりません。DOMContentLoaded
イベント発生後になる場合はありますが、load
イベント発生よりは前に実行されます。
defer属性をつけた場合
コード
<script defer src="js/index.js"></script>
HTMLパースは止まることなくJSのダウンロードが進みます。JSのダウンロードが完了してHTMLパースも完了した後、DOMContentLoaded
イベント発生の直前にJSが実行されます。言い換えるとdefer
属性をつけたJSが全て実行されるまでDOMContentLoaded
イベントは発生しません。
<script>
タグを複数記述した時の実行順序は<script>
タグを書いた順番になります。
まとめ
読み込み速度は若干ですが「defer
>async
>属性なし(デフォルト)」の順で速くなります。属性を付けないより付けた方が速いですが、async
とdefer
にそれほど大きな差はありません。けれども、async属性は「loadイベント発生よりは前ではあるがいつ実行されるか不明確」です。一方、defer属性は「確実にHTMLパースが完了した後に実行」になるのでHTMLパースを妨げることがないため読み込み速度の向上に繋がります。また、<script>
タグを複数記述していて他のJavaScriptファイルに依存し合う場合も、実行順序が決まっているdefer
属性が好ましいです。
サイト読み込みの高速化は様々な工夫のチリツモだと思うので、ある程度の高速化であっても、</body>
の直前に記述するのではなく、async
/defer
属性を付与して(個人的にはdefer
属性がおすすめ)<head>
内で読み込ませるのが良いです。