LoginSignup
10
9

More than 1 year has passed since last update.

JavaScriptのページ読み込み関連イベントの発火順序をまとめてみた

Last updated at Posted at 2022-01-21

はじめに

JavaScriptを学習していると、Webページを読み込むタイミングで処理を行うことがよくあります。

  • loadイベント(window.onload)
  • DOMContentLoadedイベント
  • defer属性を付与したscript要素

これらはブラウザのWebページ読み込み処理と関係しています。
しかし個別では理解できても、まとめると処理の順序がなかなかイメージできず、一覧にしてまとめた表があったらわかりやすいのに、と思ったので勉強がてら作ってみました。

対象者

  • ブラウザのページ読み込みとイベントの発火タイミングがイメージできない方
  • ページ読み込みに関するJavaScriptのイベント一覧が知りたい方
  • ページ読み込みに関する流れが知りたい方

前提と結論

前提として、Webページが表示されるまでの大まかな流れは以下のようになっています。

  1. HTTPレスポンスによりブラウザがhtmlファイルを受け取る
  2. 受け取ったhtmlファイルを元にブラウザがレンダリング処理を行う
  3. Webページが表示される

この記事は上記の2から3へ向かう流れを「Webページの読み込み」として、解説したものです。

結論として、処理の順番とブラウザの状態、発火するイベントや処理の流れを一覧にまとめたものが以下になります。

順番 ブラウザの状態 htmlの読み込み状態 発火するイベント・実行される処理
0 HTTPレスポンスによるhtmlファイルの受け取り - -
1 htmlファイル読み込み開始 loading -
2 htmlファイル読み込み中 loading 外部リソースの取得・通常のscript要素の実行
3 htmlファイル読み込み完了 interactive readystatechangeイベント
4 htmlファイル読み込み完了 interactive defer属性の付与されたscript要素の実行
5 htmlファイル読み込み完了 interactive DOMContentLoadedイベント
6 外部リソース読み込み開始 interactive 画像の表示等
7 外部リソース読み込み完了(Webページの表示完了) complete readystatechangeイベント
8 外部リソース読み込み完了(Webページの表示完了) complete loadイベント

処理の流れについて、実際に確認したい方はこちらのサンプルコード(Plunker)が非常に参考になります。
サンプルコード出典:JAVASCRIPT.INFO

それでは次項からこの表に至る過程について説明していきます。

※ページの読み込みについてはブラウザのレンダリングが大きく関わっています。
レンダリングについて、この記事で直接は触れませんが、理解するのにとても役立ったので調べてみるのはオススメです(参考にしたサイトのリンクは最後にまとめてあります)。

JavaScriptのページ読み込み関連イベント

はじめに、JavaScriptではページの読み込みに関連して、以下のようなイベントが発火します。

詳細についてはそれぞれのページを参照してもらうとして、それぞれのイベントの発火タイミングは以下の通りとなります。

イベント名 発火タイミング
DOMContentLoaded htmlファイルの読み込みが完了したタイミング
load htmlファイルと外部リソースの読み込みがどちらも完了したタイミング
readystatechange htmlファイルの読み込み状態が変化したタイミング

※外部リソースとはhtmlファイル内でsrc属性をつけて記述する、CSSや画像ファイルなどの外部ファイルのことです。

このうちDOMContentLoadedイベントとloadイベントについては、

  • 画像の読み込みを待たない→DOMContentLoadedイベント
  • 画像の読み込みを待つ→loadイベント

としてよく比較されており、「画像(外部リソース)の読み込みを待たない分、DOMContentLoadedイベントの方が先に処理される」というような相対的な処理順序での紹介をよく見かけます。

一方、readystatechangeイベントは、「htmlファイルの読み込み状態」の変化を検知するもので、前の2つとは異なり発火タイミングが複数あります。

この「htmlファイルの読み込み状態」は、前の2つのイベントとも関係する、ブラウザでの処理状況を表すものになります。

「htmlファイルの読み込み状況」とは

前項で、readystatechangeイベントを「htmlファイルの読み込み状態の変化を検知するイベント」と紹介しました。
ここでは「htmlファイルの読み込み状態」がなんなのかについて説明します。

「htmlファイルの読み込み状態」とは、ブラウザがhtmlファイル読み込み時にとる3つの状態のことを表します。
「htmlファイルの読み込み状態」は以下の3つです。

htmlファイルの読み込み状態 詳細
loading htmlファイルの読み込み開始〜完了までの状態
interactive htmlファイルの読み込みが完了した状態
complete htmlファイル及び外部リソースの読み込みがどちらも完了した状態

これら3つの状態を表す値はdocument.readyStateプロパティで取得できます。
つまり、readystatechangeイベントはこのプロパティの値の変化を検知して発火するイベントです。

「読み込み状態」と読み込み関連イベントとの関係

さて、前項で説明した「読み込み状態」のうちinteractiveとcompleteの「詳細」の内容について、似たような記述が前の表にも出てきました。

DOMContentLoadedイベントと、loadイベントです。

この2つのイベントは、以下のように対応しており、状態の切り替わりとほぼ同時※に発火するイベントです。
- DOMContentLoadedイベントの発火 ≒ interactive状態への切り替わり
- loadイベントの発火 ≒ complete状態への切り替わり
※イベントの発火よりも読み込み状態の切り替わりの方がわずかに早い。

これらを1つの表にまとめると以下のようになります。

htmlファイルの読み込み状態(window.readyStateの値) 読み込み状態が切り替わった時に発火するイベント 詳細
loading - htmlファイルの読み込み開始〜完了までの状態
interactive DOMContentLoadedイベント, readystatechangeイベント htmlファイルの読み込みが完了した状態
complete loadイベント, readystatechangeイベント htmlファイル及び外部リソースの読み込みがどちらも完了した状態

ここまでで、JavaScriptのページ読み込み系のイベントと、ブラウザによるhtmlファイルの読み込み処理がどのように対応しているのかについて説明しました。

続いて、ここにdefer属性を付与したscript要素の実行タイミングも加えて考えていきます。

defer属性を付与したscript要素の実行タイミング

defer属性をscript要素に付与すると、記述された処理の実行タイミングが変わります。
defer属性を付与しない場合、ブラウザによるhtmlファイルの読み込みがscript要素に届いた時点で実行されますが、defer属性を付与していると以下のように変わります。

この論理属性は、スクリプトを文書の解析完了後かつ DOMContentLoaded が発生する前に実行することをブラウザーに示します。
defer属性の付いたスクリプトは、スクリプトが読み込まれて評価が完了するまで、 DOMContentLoadedイベントの発生が抑制されます。
~中略~
defer属性のあるスクリプトは、文書に現れた順で実行されます。

出典:<script>: スクリプト要素 - HTML: HyperText Markup Language | MDN

ここでいう「文書の解析完了」というのは、これまで出てきた「htmlファイルの読み込み完了」と同義で、読み込み状態がinteractiveへと切り替わるタイミングです。
つまりdefer属性のついたスクリプトの実行タイミングは以下の順番になります。

  1. interactive状態への切り替わり
  2. defer属性の付与されたscript要素の実行(複数の場合は上から順に実行)
  3. DOMContentLoadedイベントの発火

まとめ

それでは最後に、これまで出てきたイベントや処理が発生する順番をまとめてみます。
(冒頭に出てきたものと同じ表です)

順番 ブラウザの状態 htmlの読み込み状態 発火するイベント・実行される処理
0 HTTPレスポンスによるhtmlファイルの受け取り - -
1 htmlファイル読み込み開始 loading -
2 htmlファイル読み込み中 loading 外部リソースの取得・通常のscript要素の実行
3 htmlファイル読み込み完了 interactive readystatechangeイベント
4 htmlファイル読み込み完了 interactive defer属性の付与されたscript要素の実行
5 htmlファイル読み込み完了 interactive DOMContentLoadedイベント
6 外部リソース読み込み開始 interactive 画像の表示等
7 外部リソース読み込み完了(Webページの表示完了) complete readystatechangeイベント
8 外部リソース読み込み完了(Webページの表示完了) complete loadイベント

非常に参考になるサンプルコード(Plunker)
サンプルコード出典:JAVASCRIPT.INFO

おわりに

ページ読み込みとイベントの関係については、レンダリングについて知ってから曖昧だった部分の理解が一気に進みました。
レンダリングはややこしく、まだまだ知識は浅いのですが、ブラウザの仕組みやはたらきが以前よりもずっと理解できるようになりました。
この記事が同じような悩みを持っている方の参考になれば幸いです。
もし記事の内容に誤りやアドバイス等あればコメントいただけると嬉しいです。

参考にしたサイト

(★がついているのは特に勉強になったと感じたサイトです)

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9