Java Scriptの読み込み設計(deferとDOMContentLoadedの使い分け)
はじめに
JavaScriptを書く際に毎回迷いがちなのが、
deferを使うべきかDOMContentLoadedで囲うべきか- そもそも全部囲う必要があるのか
という点。
この記事は、安全性・パフォーマンス・設計の観点から整理した備忘録としてまとめる。
DOMContentLoadedとは何か
JavaScript
document.addEventListener("DOMContentLoaded", () => {
// DOM構築完了後に実行
});- HTMLの解析
- DOMツリーの構築
がすべて完了したあとに実行されるイベント。
DOM要素を安全に操作するための待機ポイント。
DOMに依存しないコードとは
以下のような処理はDOMを必要としない。
- 定数定義
- 関数定義
- 計算ロジック
- ユーティリティ関数
- クラス定義
JavaScript
const TAX = 0.1;
const calcPrice = (price) => {
return price + price * TAX;
};これらはいつ評価されても問題ないコード。
全てをDOMContentLoadedで囲う問題点
JavaScript
document.addEventListener("DOMContentLoaded", () => {
const TAX = 0.1;
const calcPrice = (price) => {
return price + price * TAX;
};
});この書き方では、DOM非依存の処理までDOM構築完了を待つことになる。
不要な待機が発生する。
deferの挙動整理
HTML
<script src="main.js" defer></script>- JSファイルはHTML解析中に読み込まれる
- 実行はDOM構築完了後
特徴:
- DOM操作が安全
- ファイル全体が一律で待たされる
DOM非依存コードも遅れる。
設計の考え方
重要なのは次の分離。
- DOMに依存しないコード:できるだけ早く評価
- DOMに依存するコード:必要なタイミングまで待つ
この2つを混ぜない。
安全性とパフォーマンスを両立する構成
ファイルを役割で分ける
logic.js:DOM非依存(計算・設定・関数)ui.js:DOM操作専用
logic.js(deferまたは通常読み込み)
JavaScript
// DOMに依存しない処理
export const calcPrice = (price) => price * 1.1;- DOMを触らない
- 早期評価して問題なし
ui.js(DOMContentLoaded)
JavaScript
document.addEventListener("DOMContentLoaded", () => {
const btn = document.querySelector(".btn");
btn.addEventListener("click", () => {
console.log(calcPrice(100));
});
});- DOM操作のみをここに集約
- 安全性が高い
この構成のメリット
- DOM未生成バグが起きない
- 不要な待機を減らせる
- ロジックとUIが明確に分離される
- 再利用・テストしやすい
安全性とパフォーマンスのバランスが良い。
注意点
- 小規模サイトではやりすぎになる場合がある
- ファイル管理・enqueueがやや複雑
規模と目的に応じて選択する。
WordPress前提での判断基準
- 小〜中規模:
- 1ファイル +
defer
- 1ファイル +
- 中〜大規模 / 設計重視:
- ロジックとUIを分離
- DOM操作のみ
DOMContentLoaded
まとめ
- 全てを
DOMContentLoadedで囲うのは非効率 deferは安全だが一律待機- 最適解は役割分離
「DOMを触るものだけ待たせる」
この考え方を基準に設計する。