【JavaScript】ページ読み込み後に一度だけ実行される処理の書き方

【JavaScript】ページ読み込み後に一度だけ実行される処理の書き方 JavaScript

「ページを開いたときに一度だけ実行したい」処理は、いつ実行されるか(タイミング)を意識すると安定します。DOMがまだ無いうちに要素を操作しようとして失敗する、というのはよくあるミスです。

この記事の結論:DOM操作なら DOMContentLoaded(または defer スクリプト)。画像など全リソースを待つなら load。なお、「ページを開くたび毎回」と「初回アクセスだけ」は別物で、後者は localStorage で制御します。
スポンサーリンク

基本:DOMContentLoaded(DOM構築後・推奨)

HTMLのDOM構築が終わった時点で実行されます。画像の読み込みを待たないため速く、DOM操作やUI初期化はこれで十分です。

JavaScript:DOMContentLoaded
document.addEventListener("DOMContentLoaded", () => {
  console.log("DOMの構築が完了しました");
  // 要素の取得・表示切り替えなど
});

画像まで待つ:load

画像・CSS・スクリプトなどすべてのリソースが読み込まれた後に実行したいときはload イベントを使います。サイズ計算など画像の読み込みが必要な処理に向いています。

JavaScript:load
window.addEventListener("load", () => {
  console.log("ページの読み込みが完了しました(画像も含む)");
});

イベントを使わない方法:deferスクリプト

実は、<script>defer を付けるか、<body> の最後に置けば、DOM構築後に実行されます。この場合 DOMContentLoaded で囲まなくてもDOM操作ができます。type="module" のスクリプトも同様に defer 相当で動きます。

HTML:deferでDOM構築後に実行
<!-- head に置いてもDOM構築後に実行される -->
<script src="app.js" defer></script>

<!-- type="module" も defer 相当 -->
<script type="module" src="app.mjs"></script>

落とし穴:発火後に登録すると動かない(readyState)

よくあるバグ:DOMContentLoadedすでに発火した後にリスナーを登録すると、イベントは二度と発火しないため処理が実行されません。非同期(async)で読み込まれるスクリプトなどで起こりがちです。document.readyState で状態を確認し、すでに構築済みならその場で実行します。
JavaScript:発火済みでも確実に動かす
function init() {
  // DOM操作・初期化処理
}

if (document.readyState === "loading") {
  // まだ読み込み中 → イベントを待つ
  document.addEventListener("DOMContentLoaded", init);
} else {
  // すでに構築済み → 即実行(これが無いと動かないことがある)
  init();
}

これは jQuery の $(function(){}) が内部でやっていることと同じで、いつ読み込まれても確実に動く安全な書き方です。

↓ いま見ているこのページの実際の状態です(readyState はloading → interactive → complete と変化します):

  • document.readyState
  • DOMContentLoaded:
  • load(全リソース):

「毎回」と「初回アクセスだけ」は違う

DOMContentLoadedloadページを開くたびに毎回実行されます。「初回アクセスのときだけ」にしたいなら、localStorage にフラグを保存して制御します。

JavaScript:初回アクセスだけ実行
document.addEventListener("DOMContentLoaded", () => {
  if (!localStorage.getItem("visited")) {
    // 初回だけ実行したい処理
    localStorage.setItem("visited", "true");
  }
});
alertよりUIで:ウェルカム表示に alert() を使うと操作を止めてしまいます。実際は要素の表示で見せるのがおすすめです。初回訪問時だけ要素を見せる具体的な方法(リセットや期限付き表示を含む)は初回訪問時のみ要素を表示する方法localStorage の基本はlocalStorageの使い方完全ガイドを参照してください。

jQueryを使っている場合(ready)

jQueryなら $(document).ready()(または短縮形)で、DOMContentLoaded と同じタイミングで実行できます。

JavaScript:jQueryのready
$(function () {
  console.log("jQueryでページ読み込み完了");
});

方法の使い分け(まとめ表)

方法 実行タイミング 用途
DOMContentLoaded DOM構築後(速い) DOM操作・UI初期化(基本これ)
load 全リソース読み込み後 画像サイズ計算など
defer / 末尾に配置 DOM構築後 イベントで囲まずに実行
localStorage 併用 初回アクセス時だけ 「一度きり」の制御
jQuery $(function(){}) DOM構築後 jQuery使用時

よくある質問(FAQ)

Qページ読み込み後に一度だけ実行するには?
ADOMContentLoaded または load のコールバックに書きます。DOMContentLoaded はDOM解析完了後、load は画像など全リソースの読み込み完了後に発火します。どちらもページを開くたびに1回実行されます。
QDOMContentLoadedとloadの違いは?
ADOMContentLoaded はHTMLのDOM解析が終わった時点、load は画像・CSS・スクリプトなど全リソースが読み込まれた後に発火します。DOM操作なら DOMContentLoaded で十分なことがほとんどです。
QDOMContentLoadedで囲まなくてよい場合は?
Aスクリプトに defer を付けるか、<body> の最後に置けばDOM構築後に実行されるため、DOMContentLoaded で囲まなくてもDOM操作ができます。type="module" も同様です。
Q初回アクセスのときだけ実行するには?
AlocalStorage にフラグを保存し、無いときだけ処理します。DOMContentLoaded 等は毎回実行されるので、「一度きり(初回のみ)」にしたいときは localStorage を併用します。
QDOMContentLoadedを書いたのに処理が動きません。なぜ?
AスクリプトがDOMContentLoadedの発火後に読み込まれた可能性があります。イベントは一度きりなので、発火後に登録しても動きません。if (document.readyState !== "loading") { init(); } のように、すでに構築済みなら即実行する分岐を入れると確実です。

まとめ

ページ読み込み後の処理は、DOM操作なら DOMContentLoaded(または defer スクリプト)、画像まで待つなら load が基本です。

DOMContentLoaded / load毎回実行されます。「初回アクセスのときだけ」にしたいなら localStorage で制御しましょう。タイミングを正しく選んで、安定した処理にしましょう。