JavaScript ファイルの読み込み方
JavaScript ファイルを読み込むためには script
タグを使用するわけですが、
その script
タグの書き方をほんの少し変えるだけで処理速度は大きく変わってしまいます。
そこで、JavaScript ファイルの読み込み方をまとめておきます。
誰かのお役に立てば幸いです。
方法1:head タグの中で読み込む(デフォルト)
まずは、最も基本的な、script
タグを head
タグの中で読み込む方法です。
いわゆる普通の HTML の書き方ですね。
HTML を勉強したらまずはこの書き方を教わることでしょう。
ですが、この方法には1つ問題があります。
script
タグが HTML パースをブロックしてしまい(パーサーブロッキング)、
JavaScript の読み込みと処理に時間がかかってしまって、画面の表示が少し遅れてしまうのです。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="/example1.js"></script> // ① <script src="/example2.js"></script> // ② </head> <body> (省略:とっても長いHTML)// ③ </body> </html>
方法2:body タグの最下部で読み込む
方法1では、HTML パースをブロックしてしまい画面の表示が遅くなってしまうという問題がありました。
そこでその対策として、script
タグを body
タグの一番最後に記述するという方法が生まれました。
script
タグが HTML パースをブロックしてしまうのであれば、
それを後回しにすれば良いじゃないかというアプローチですね。
body
タグの一番最後に script
タグが記述されていれば、
script
タグが HTML パースをブロックしても、
その時点では既に画面の表示は終わっているという状態になってるので、
方法1よりも早く画面が表示されるのです。
この方法はとても簡単にできるので、よく使われている方法なのではないでしょうか。 かなり良い方法ではあるのですが、実はこの方法は完璧ではありません。 まだ改善の余地があります。 後述の方法3もしくは方法4を検討してみてください。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> (省略:とっても長いHTML)// ① <script src="/example1.js"></script> // ② <script src="/example2.js"></script> // ③ </body> </html>
方法3:head タグの中で defer 属性を付けて読み込む
方法2は方法1よりも早く表示されるとはいえ、HTML パースが中断されることに変わりはありません。
そこで登場するのが、defer
属性です。
script
タグに defer
属性を使用すると、HTML パースを中断させることなく、HTML パースと並行して JavaScript を読み込んでくれるようになります。
ブラウザは HTTP を使用して JavaScript ファイルをサーバーからダウンロードするわけですが、
ブラウザは HTTP のリクエストを送ったら、そのレスポンスが返ってくるまで、待つことしかやることが無いのです。
そこで、そのレスポンスが返ってくるまでの間に HTML をパースしてしまおうというアプローチです。
defer
属性を使用すると、HTML パースが中断しなくなるため、方法2よりもトータルの処理速度が速くなります。
しかも、JavaScript が実際に実行されるのは HTML パースの後になります。
つまり、DOM の構築が完了した後です。
そのため、DOMContentLoaded
イベントを待つといった処理が必要なくなります。
「defer」は日本語で「延期」という意味です。 つまり、JavaScript ファイルの読み込みだけを先に済ませて、実行は HTML パースの後に延期してくれるのです。 複数の JavaScript ファイルがある場合は、これまでと同様に HTML に記述した順番で実行してくれます。 良いことづくめなのではないでしょうか。
なお、defer
属性を使用する場合は、script
タグは head
タグの中に置いた方が良いでしょう。
defer
属性を使用するのは、HTML パースを中断させることなく、HTML パースと並行して JavaScript を読み込んで、処理速度を上げることが目的です。
つまり、JavaScript ファイルへの HTTP リクエストを早く送ることができれば、並行で処理できる時間がそれだけ長くなるため効果的なのです。
方法2のように body
タグの一番最後に置いたりしていると、並行で処理できる時間が無くなってしまい、defer
属性を使用する意味がなくなってしまうので注意してください。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script defer src="/example1.js"></script> // ① <script defer src="/example2.js"></script> // ② </head> <body> (省略:とっても長いHTML)// ③ </body> </html>
方法4:async 属性を付けて読み込む
方法3では処理速度を向上させるために、実行されるファイルの順番やタイミングが決まっていましたが、
そういった制約が全く必要ない JavaScript ファイルというのも存在します。
script
タグに async
属性を使用すると、JavaScript ファイルが非同期で読み込まれるようになります。
script
タグが見つかったタイミングで読み込みが開始されますが、非同期なので、どのタイミングで実行されるかわかりません。
JavaScript ファイルが早いタイミングでダウンロードされれば早いタイミングで実行されますし、遅いタイミングでダウンロードされれば遅いタイミングで実行されます。
複数の JavaScript ファイルがある場合の処理の順番も保証されません。
なお、JavaScript の実行中は HTML のパースは中断されます。
用途としては、他の JavaScript ファイルとの依存関係がなく、単体で実行されても問題がないものに利用します。 例えば、Google AdSense などの広告表示や、Google Analytics などのアクセス解析、Twitter などのシェアボタンやタイムラインの埋め込みなどが良い例です。
読み込まれた JavaScript はどんなタイミングで実行されるかわかりませんので、
どんなタイミングで実行されたとしても問題が無いような JavaScript ファイルにしておく必要があります。
場合によっては、DOM 構築の完了を待つために、方法2と同様に body
タグの一番最後に置いたり、
jQuery を使用しているのであれば ready()
に登録して呼ばれるのを待つなどの対応が必要になるかもしれません。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script async src="/example1.js"></script> // ① <script async src="/example2.js"></script> // ② </head> <body> (省略:とっても長いHTML)// ③ </body> </html>
まとめ
基本的には、head
タグの中で defer
属性を付けて読み込むのが良いのではないでしょうか。