この記事では、JaveScriptの記述や読み込みはどこでするべきかということについてまとめました。
僕自身、head内に書くべきかbody内末尾に書くべきかわからなかったため、今後記述するときの迷いを解消するため備忘録に残します。
JavaScriptの記述位置はbodyの終了タグの直前
JavaScriptの記述位置は、下記のようにbodyの終了タグの直前に書くのが一般的です。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイトル</title>
</head>
<body>
<!-- ここにHTML要素を記述します。 -->
<script src="sample.js"></script>
<script>
<!-- ここにJavaScriptのプログラムを記述します。 -->
</script>
</body>
</html>
理由は、HTML要素をすべて読み込んだ後に、JavaScriptを実行できるからです。
下記のように、head内でJavaScriptを読み込んだ場合、
- bodyタグ内の処理と表示の前にJavaScriptの処理・実行されbodyタグ内の表示に時間がかかる。
- JavaScriptでbodyタグ内の要素を処理する場合に、bodyタグ内の要素が処理されていないため、JavaScriptでbodyタグ内の要素を処理できず、エラーとなる。
という問題が発生するからです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイトル</title>
<script src="sample.js"></script>
<script>
<!-- ここにJavaScriptのプログラムを記述します。 -->
</script>
</head>
<body>
<!-- ここにHTML要素を記述します。 -->
</body>
</html>
bodyタグ内の処理前に実行したいJavaScriptがある場合はheadに記述
- JavaScriptでbodyタグ内の要素を処理しない
- bodyタグ内の処理前に実行したいJavaScriptがある
という場合には、heaタグ内にJavaScriptを記述しなければなりません。
つまり、JavaScriptでの処理内容に応じて、記述位置を変えたほうが良いことになります。
記述位置を1ヵ所にまとめたい場合には『async』属性や『defer』属性を追加
ここまで解説してきて、bodyの終了タグの直前とhead内でかき分けるのは非効率でわかりにくいということがあるはずです。
そんなときのために、『async』属性と『defer』属性があります。
通常、bodyの終了タグの直前にJavaScriptを記述した場合、bodyタグ内のHTMLの読み込み、JavaScriptの読み込みと実行は下記のような順番で行われます。
- (script開始タグまでの)HTMLの読み込み
- HTMLの読み込みを中断しscriptタグ内のJavaScriptを読み込み・実行
- JavaScriptの実行完了後、HTMLの読み込み再開
『async』属性や『defer』属性を追加することで、head内にJavaScriptを記述しても、HTML読み込み後に実行されるので、head内にまとめて記述しつつ、処理のタイミングは分けることができます。
async属性を追加した場合
<script src="sample.js" async></script>
<script async>
<!-- ここにJavaScriptのプログラムを記述します。 -->
</script>
上記のようにasync属性を追加した場合、JavaScriptの読み込みは、HTMLの読み込みと並行して行われ、JavaScriptの読み込みが完了し次第、HTMLの読み込みを中断し、JavaScriptを実行します。
つまり、JavaScriptの読み込みと処理を非同期に行うことができるということになります。
読み込みと実行は下記のような順番で行われます。
- (script開始タグまでの)HTMLの読み込み
- HTMLとscriptタグ内のJavaScriptを並行して読み込み
- JavaScriptの読み込み完了後、JavaScriptを実行
- JavaScriptの処理完了後、残りのHTMLの読み込み再開
JavaScriptの読み込み間もHTMLの読み込みを中断しないため、デフォルトの状態よりも処理にかかる時間を短縮することができます。
ただ、すべてのHTMLの読み込み完了前にJavaScriptが実行される可能性があるため、JavaScriptが実行されることによりHTMLの読み込みが中断される事や、読み込まれていないHTMLをJavaScriptが処理できずエラーを起こしてしまう可能性があります。
また、非同期読み込みであるがゆえにJavaScriptの記述順に処理が実行されるわけではないので、複数のJavaScriptを読み込む場合には不向きです。
defer属性を追加した場合
<script src="sample.js" defer></script>
<script defer>
<!-- ここにJavaScriptのプログラムを記述します。 -->
</script>
上記のようにdefer属性を追加した場合、JavaScriptの読み込みは、HTMLの読み込みと並行して行われ、JavaScriptの読み込みとHTMLの読み込みが完了した後、JavaScriptを実行します。
つまり、JavaScriptをHTMLと並行して読み込み、実行は遅らせることができます。
読み込みと実行は下記のような順番で行われます。
- (script開始タグまでの)HTMLの読み込み
- HTMLとscriptタグ内のJavaScriptを並行して読み込み
- JavaScriptとHTMLの読み込み完了後、JavaScriptを実行
asyncと違い、HTML読み込み後にJavaScriptが実行されるため、head内に記述してもJavaScript実行時にHTMLが読み込まれていない状況がなくエラーを防ぐことができます。
終わりに
JavaScriptの記述位置は基本的に、bodyの終了タグの直前が良いです。
ただ、場合によってhead内に記述する必要があり、記述位置をhead内の1ヵ所にまとめたいという方は、asyncやdeferを使うことで実行タイミングを変えエラーを防ぐことができます。
僕自身めんどくさがりでできるだけエラーを起こしたくないので、head内にまとめるとしてもdeferを使っていく予定です。
asyncとdeferをJavaScriptによって変えて使うのも面白そうなので、いつか試して処理速度を計測してみます。
Coment