DOMContentLoadedとloadはDOM解析完了か画像を含む読込完了かで使い分ける
公開日: 執筆:佐藤
HTMLから作られるDOMを操作するだけなら、DOMContentLoadedを使います。画像など、ページ表示に必要な外部資源の読込完了を待つ処理なら、loadを使います。
loadへ処理を集めればよいわけではありません。DOMだけで実行できる処理まで画像の読込を待つと、操作開始が遅れます。反対に、画像の寸法が必要な処理をDOMContentLoadedで始めると、まだ読み込まれていない画像を測る可能性があります。
DOMContentLoadedはDOMを組み立てた後に発生する
HTML5の読み込み手順では、HTMLの解析を終えると文書の状態をinteractiveへ変え、解析終了後に実行するスクリプトを処理してから、DocumentへDOMContentLoadedを発生させます。
その時点では、画像などの外部資源が読み込み中でも構いません。要素の取得、class名の追加、クリック処理の登録など、DOMがあれば始められる処理に向きます。
function prepareMenu() {
var menu = document.querySelector('.global-menu');
if (menu !== null) {
menu.classList.add('is-ready');
}
}
document.addEventListener('DOMContentLoaded', prepareMenu, false);
これは説明用の仮例です。DOMContentLoadedはDocumentへ登録します。HTML内に対象要素があるかを確認し、見つかった場合だけ操作します。
loadは読込を遅らせる外部資源を待って発生する
HTML5の手順では、DOMContentLoadedの後、文書のloadを遅らせるものがなくなるまで待ちます。その後、文書の状態をcompleteへ変え、Windowへloadを発生させます。
画像を含む表示資源の読込後に寸法を使う処理は、loadへ登録します。
function showPhotoWidth() {
var photo = document.getElementById('main-photo');
var output = document.getElementById('photo-width');
if (photo !== null && output !== null) {
output.textContent = photo.width;
}
}
window.addEventListener('load', showPhotoWidth, false);
このコードも説明用の仮例です。画像要素と出力先の両方を変数へ取り、nullでないことを確かめます。
| 処理 | 選ぶイベント | 理由 |
|---|---|---|
| 要素を取得してclass名を付ける | DOMContentLoaded |
DOMが組み上がれば実行できる |
| ボタンへクリック処理を登録する | DOMContentLoaded |
対象要素があれば実行できる |
| 画像の読込後に寸法を測る | load |
画像の読込完了が条件になる |
| ページ全体を読込中表示から切り替える | load |
何を待つかを定義したうえで完了を扱う |
待つ対象を「ページ全部」という言葉だけで決めず、処理にDOMだけが必要か、外部資源も必要かを分けます。
document.readyStateでイベントが終わっていないか確認する
イベントを登録するコードが常にHTML解析中に実行されるとは限りません。別のスクリプトが後から読み込む場合や、処理を遅れて呼び出す場合は、登録前にDOMContentLoadedが終わっている可能性があります。
document.readyStateには、loading、interactive、completeの三つの状態があります。HTML5のDocument定義では、解析中をloading、解析済みで外部資源を読み込み中の状態をinteractive、読込完了をcompleteとしています。
DOMを使う初期化処理は、次のように分けられます。
function initializePage() {
// DOMを使う初期化処理
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializePage, false);
} else {
initializePage();
}
loadingならイベントを待ち、interactiveまたはcompleteならDOMは解析済みなので、すぐ実行します。これにより、イベント登録が間に合わず、初期化処理が一度も動かない状態を避けられます。
画像を含む読込完了が必要なら、completeかどうかで分けます。
if (document.readyState === 'complete') {
showPhotoWidth();
} else {
window.addEventListener('load', showPhotoWidth, false);
}
一つの初期化処理を二つのイベントへ重ねない
同じ関数をDOMContentLoadedとloadの両方へ登録すると、一回だけ行うつもりの処理が二回動きます。イベントを増やす前に、処理を次の二つへ分けます。
- DOMがあれば実行できる処理
- 画像などの読込完了が必要な処理
それぞれを別の関数にし、必要なイベントへ一度だけ登録します。対応ブラウザーは仕様書だけでは決まりません。公開前に、対象とするブラウザーでイベントの順序、要素の取得、画像寸法、二重実行がないことを確認します。
まず既存のwindow.onloadへ登録している処理を一つ選んでください。画像や外部資源を使わず、DOMだけで完了する処理なら、DOMContentLoadedへ分けられるかを確認します。
関連記事

