CODE JavaScript

【JS】 DOMContentLoaded と load の違いを新人でもわかるように解説

JSのイベントリスナーでDOMContentLoadedとloadがあるけど何が違うんだろう?どう使い分けたらいいんだろ?

JSイベントの設定でよく見かけるDOMContentLoadedとloadがありますが、それぞれ違いを理解した上で使い分けられていますでしょうか?

この二つの違いは発火のタイミングです。
この理解が無いと想像通りの挙動をしてくれないことがあります。

では詳しく解説していきます。

Webページの読み込み順を理解しよう

細かいところ解説していくと長くなるので、とりあえずこの2段階を知っていれば大丈夫です。

①DOMツリーを読み込む
②画像、CSSなどの外部ファイルの読み込み完了

①の時に全てのHTMLタグを樹形図のように表し、その構造(テキスト情報も含む)を書き出します。
まずページ全体の骨格を作っていると思っておいてOKです。

②ではその骨格の形成が完了した後に使われている画像やCSSを読み込んでページを完成させていきます。

ネット環境がめちゃくちゃ悪いところで何かのページを見ると、まず文章構造(文字や改行)だけが反映されて、その後にCSSが適用されて画像が読み込まれますよね。
これは重要なポイントです。

では本題に入っていきましょう。

DOMContentLoadedはDOMツリー読み込み完了後に発火

DOMContentLoadedはDOMの読み込みが完了してから発火します。

document.addEventListener('DOMContentLoaded',
  function(){
    console.log('DOMツリーの解析が終わりました。');
  }
);

上記の場合DOMツリーの読み込みが終わって、画像やCSSが読み込まれる前に「DOMツリーの解析が終わりました。」と出てきます。

ここで知っていて欲しいことは、
<script>タグの読み込みはHTMLの</body>直前に記述する場合、改めてDOMContentLoadedの設定は不要ということです。
なぜかというと、

Webの仕組みでページの読み込みはHTMLファイルの上から順番に読み込んでいくので、
HTMLの下部に<script>タグ入れておくと、<script>タグが読み込まれるまでにすでにDOMの読み込みが完了しているからです。(正確には<script>タグ以降に他の閉じタグの2,3行は残っているかもですが)

したがって、わざわざDOMの読み込み完了後に「DOM読み込み完了時にイベント発火させる」という記述は不要なのです。
だって対象のJSファイルが読み込まれる時にはもうDOMの読み込み終わってるんだし。

逆にDOM操作をするJSを<head>の中に書いている場合はDOMContentLoadedを使っていないと、エラーになる可能性があります。後述しますがloadイベントでも大丈夫です。

理由はDOM読み込みが終わっていないのにDOM操作をしようとするからです。
その状態では操作対象のDOMはNull(なにもない)になって返ってきます。

JS:「さぁ、DOMを操るぞー!、、あれ?目当てDOMが見つからない,,,??」
HTML:「だってまだDOMを全部読み切ってないもん。
JS:「そっか。じゃあNull出しとく!

みたいな感じです。

<head>にJSを記述する際の注意点は、JSの読み込みが完了しないとHTMLの読み込みも再開されないという点です。
よって長いJSの記述をしているとページ表示に時間がかかってしまいユーザーの離脱に繋がる可能性があるので気をつけましょう。

loadはDOMContentLoadedよりも後に発火

loadイベントはDOM読み込みだけではなく、画像やCSS等の外部ファイルもすべて読み込みが完了してから発火します。
よって「load」の方が「DOMContentLoaded」よりイベントの発火タイミングが遅いです。

こんな順序でイベントが発火します。

window.addEventListener('load', function(){
  console.log('ページの読み込みが完了しました。');
});

こうすると、DOMツリーの読み込みが終わってかつ、画像も完全に読み込みが終わってから「ページの読み込みが完了しました。」と表示されます。

例えばページ読み込み時にローディングを実装して、ページが完全に読み込こまれたらそのローディングを消すとかに使えそうですね。
こんなやつ↓↓

実際にDOM ContentLoadedとloadの発火タイミングを比較してみましょう。

window.addEventListener('load', function(){
  console.log('ページの読み込みが完了しました。');
});

document.addEventListener('DOMContentLoaded',
  function(e){
    console.log('DOMツリーの解析が終わりました。');
  }
);

このように記述すると、本来は上から順番に実行されるので、
①「ページの読み込みが完了しました。」
②「DOMツリーの解析が終わりました。」
の順に表示されるかと思います。

ですが、実際は
ページの読み込み完了の方がDOM解析より時間がかかるので、
①「DOMツリーの解析が終わりました。」
②「ページの読み込みが完了しました。」
の順番に表示されます。

検証結果↓

ちなみに、
loadイベントだとwindow.addEventListener
DOMContentLoadedイベントだとdocument.addEventListener
と記述されておりwindowとdocumentの部分が違っています。
これはそれぞれのイベントがwindowオブジェクトとdocumentオブジェクトに対して動作しているからです。

ここではサラッとだけ解説します。
windowオブジェクトとはJSが動作しているブラウザのwindowを指しています。
documentオブジェクトとはDOMを指しています。

loadイベントがwindowとなっているのはページロード自体がブラウザ全体に関係しているからです。
一方、DOMContentLoadedイベントはDOM関連の読み込みだけが必要なのでdocumentとなっています。

今回は以上となります。
皆さんのJSの理解に繋がっていれば幸いです。
では!




▼▼人気の記事▼▼

【経験談】給料を上げたいなら自分に対しての出費を増やそう【自己投資のススメ】

-CODE, JavaScript
-, , , ,