スライドショー

【JavaScript入門】onloadイベントの使い方とハマりやすい注意点とは

こんにちは、ライターのマサトです!

初めてJavaScriptでDOMを扱うようになってくると、実行タイミングがズレてエラーになることがよくあります。

この場合、ほとんどの理由がHTML(DOM)のレンダリングとタイミングが合っていないことに起因します。これを上手く解消するには、HTML内の書く場所に注意したり、「onloadイベント」の正しい書き方を知る必要があります。

しかしながら、「実行タイミング」についてはいろんな罠が潜んでいるため、この記事で正しい知識を身につけてスッキリと理解できるようにしておきましょう。

【罠その1】JavaScriptは書く場所によってエラーになる!

まずは基本的なことですが、HTMLのソースコードは上から下へ順番に読み込まれて解析されていきます。

当然ながら、HTMLの中にはJavaScriptも存在しており、どの場所に書くかによって結果が変化することがあります。

JavaScriptを書く場所としては、大きく分けると「head要素内」と「body要素内」の2箇所があります。

javascript-onload-tutorial-02

基本的には「body要素内」にJavaScriptを書くことが多いのですが、その理由も合わせてもう少し詳しく見ていきましょう!

「head要素内」に書く場合

まずは、「head要素内」に書く場合について見ていきます。

基本的な書き方としては、以下のとおりです!

<html>
  <head>

    <!-- ここからJavaScriptファイルの読み込み -->
    <script src="jquery.js"></script>
    <script src="bootstrap.js"></script>
    <script>
        var items = ['ねこ', 'いぬ', 'とり'];

        for(var i=0; i<items.length; i++) {
            console.log(items[i]);
        }
    </script>

  </head>
  
  <body>
      <div id="container">
        <h1>サンプルページ</h1>
      </div>
  </body>
</html>

上記の例では、「jquery.js」や「bootstrap.js」などの外部ファイルを読み込んだり、「scriptタグ」内に直接コードを書いています。

このように、「head要素内」にJavaScriptを書くことはできますが、すべての読み込みが完了しないとDOMがレンダリングされないのでWebページの表示が遅くなってしまうというデメリットがあります。

「body要素内」に書く場合

次に、「body要素内」にJavaScriptを書く場合について見ていきます。

先ほどのコードを利用すると、以下のとおりになります。

<html>
  <head>
  </head>
  
  <body>
      <div id="container">
        <h1>サンプルページ</h1>
      </div>


    <!-- ここからJavaScriptファイルの読み込み -->
    <script src="jquery.js"></script>
    <script src="bootstrap.js"></script>
    <script>
        var items = ['ねこ', 'いぬ', 'とり'];

        for(var i=0; i<items.length; i++) {
            console.log(items[i]);
        }
    </script>

  </body>
</html>

ポイントはbodyの閉じタグの直前に記述するという点です。

こうすることで先にDOMのレンダリング始まり、Webページが表示された後にJavaScriptが読み込まれるので、体感的に速く表示されると感じるわけです。

javascript-onload-tutorial-03

このような理由から、基本的にJavaScriptは「body要素内」に書くことが多い傾向にあります。

HTMLの中で読み込むJavaScriptのファイルには自分で作成したファイルの他に外部の人が作成したファイルを読み込む場合など様々なケースがあります。

そのあたりの詳しい内容は以下の記事にてご紹介していますので、ぜひ参考にしてみてください。

HTMLとJavaScriptの関係とは?|呼び出し・制御方法について解説
更新日 : 2019年10月11日

JavaScriptがエラーになる書き方

先ほどは「書く場所」について学びましたが、今度は「書き方」についてもう少し見ていきましょう!

例えば、よくある間違いとして「head要素内」から「pタグ」のDOMを取得しようとした事例がコチラ!

<head>
<script>
    var memo = document.getElementById('memo');

    memo.textContent = 'こんにちは!';
</script>
</head>
<body>
    <p id="memo"></p>
</body>

このコードはエラーになります。

理由は冒頭でも書きましたが、HTMLは上から下へ順番に読み込まれて解析されるからです。

つまり、JavaScriptを読み込んだ時点では、まだ「pタグ」が存在していないのに文字列を代入しようとしているため、「pタグなんてないよ!」というエラーになるわけです。

そこで、「body要素内」に同じコードを書いてみましょう!

<head>
</head>
<body>
    <p id="memo"></p>


    <script>
        var memo = document.getElementById('memo');

        memo.textContent = 'こんにちは!';
    </script>
</body>

今度はエラーになりません。

なぜなら、JavaScriptが読み込まれる前にDOMがレンダリングされており、「pタグ」が存在しているからですね。

ただし、bodyの閉じタグ直前に書いたからといって、必ずDOMのレンダリングが完了していることは保証されていません。

そのため、DOMを扱う場合には次の項目以降でご紹介する「onloadイベント」を利用するのがベストな選択となります!

【罠その2】onloadイベントは書き方次第で実行されなくなる!

先ほどの項目で、JavaScriptの「書く場所」「書き方」について学びました。

そして、DOMを扱うのであれば、最終的に「onloadイベント」を利用するのがベストな選択肢になるわけですが、こちらも書き方について注意するべきポイントがあるので詳しく見ていきましょう!

window.onloadについて

まずは、「onloadイベント」の基本的な書き方について学んでいきましょう。

一般的には「window.onload」に関数を代入するカタチで書いていきます。

window.onload = function() {

    // 実行したい処理を書く

}

このように書くことで、すべてのDOMツリー構造及び関連リソースが読み込まれたあとにJavaScriptが実行されるようになります。

つまり、「head要素内」でDOMを扱うプログラムを書いてもエラーにはなりません。(もちろん「body要素内」でもOK)

<head>
<script>
    window.onload = function() {
        var memo = document.getElementById('memo');

        memo.textContent = 'こんにちは!';
    }
</script>
</head>
<body>
    <p id="memo"></p>
</body>

上記コードは、普通に書くとエラーになりかねませんが、「onloadイベント」を利用することで正常に動作します。

また、「bodyタグ」に直接「onloadイベント」を記述することも可能です!

<head>
</head>

<!-- bodyにonloadイベントを設定 -->
<body onload="start()">
    <p id="memo"></p>


    <script>
        function start() {
            var memo = document.getElementById('memo');

            memo.textContent = 'こんにちは!';
        }
    </script>
</body>

あらかじめJavaScriptで関数を作成しておき、それを「bodyタグ」の「onloadイベント」で実行すれば良いわけです。

このように「onloadイベント」を覚えると、JavaScriptの「書く場所」を意識しなくてもDOMを扱えるようになるので非常に便利ですね!

複数のwindow.onloadを書いた場合

「onloadイベント」はとても便利なのですが、注意するべきポイントもあります。

それは、複数の「onloadイベント」書いてしまうと上書きされてしまい、最後に書いたイベントだけが実行されるという仕様によるものです。

例えば、次のように書いた場合、「コンソールログ」には何が表示されるでしょうか?

window.onload = function() {
    console.log('ミカン');
}
window.onload = function() {
    console.log('バナナ');
}
window.onload = function() {
    console.log('メロン');
}

正解は、「メロン」です!

「window.onload」は関数を代入するという特性上、最後に代入された関数が上書きされて実行されるわけです。これは、簡単に言うと「変数」に「値」を代入する行為に似ているでしょう。

このような特性があることによって、複数人でプログラムを書いている場合に誤って「onloadイベント」を上書きしてしまうリスクがあるので注意が必要です。

そこで、このようなリスクを考慮しないイベント処理の書き方が存在しており、それが「addEventListener()」を使った方法です!

先ほどのコードを「addEventListener()」に置き換えるとこうなります!

window.addEventListener('load', function() {
  console.log('リンゴ');
})
window.addEventListener('load', function() {
  console.log('バナナ');
})
window.addEventListener('load', function() {
  console.log('メロン');
})

コンソールログには…

リンゴ
バナナ
メロン

という感じで、すべて出力されているのが分かります!

つまり、複数の「onloadイベント」を登録してもすべて実行されるようになっているわけですね。

【罠その3】onloadイベントは意外に遅い!

これまでに「onloadイベント」として、「window.onload」と「addEventListener()」の2種類を学んできました。

どちらにしても、「onloadイベント」はDOMのレンダリングやCSS・画像などの関連リソースをすべて読み込んだ後に実行される処理でした。

しかしながら、大抵の場合はDOMの「ツリー構造」さえ完了していればJavaScriptからDOMを扱えるので、すべてのリソースを読み込むまで待つ必要はないはずです。

そこで、知っておくと便利に使えるのが「DOMContentLoadedイベント」です。これはDOMの「ツリー構造」が完了した時点で実行されるので、通常の「onloadイベント」よりも速く動作するというメリットがあります。

一般的な書き方は次のとおり!

window.addEventListener('DOMContentLoaded', function() {

    // 実行したい処理を書く

})

書き方は「onloadイベント」によく似ていますね。

それでは、先ほどのサンプルコードに「DOMContentLoaded」を使ってみましょう!

window.addEventListener('load', function() {
  console.log('リンゴ');
})
window.addEventListener('load', function() {
  console.log('バナナ');
})
window.addEventListener('DOMContentLoaded', function() {
  console.log('メロン');
})

最後のイベント処理だけ「DOMContentLoaded」を使っていますが、出力結果はどうなると思いますか?

正解は以下のとおり!

メロン
リンゴ
バナナ

という順番で表示されます。

つまり、「メロン」のイベント処理だけが「DOMContentLoaded」を利用しているので、最も速く実行されたというわけです!

【罠その4】画像の読み込みには時間がかかる!

さて、これまではDOMを扱った事例を見てきましたが、少しステップアップした応用編として、今度は「画像ファイル」の扱いについて見ていきましょう!

JavaScriptから画像を読み込んで処理するケースにおいて、実はDOMを扱う事例と同じような現象が発生します。このあたりの事情について、知っているのと知らないのではかなり差がつくのでしっかりと学んでおきましょう!

基本的な画像の読み込み方!

まずは、JavaScriptから画像ファイルを読み込む方法について見ていきましょう!

一般的な書き方としては、「Image()」コンストラクタを使ってインスタンス化する方法です。

var img = new Image();  // インスタンス化

img.src = 'image/sample.jpg';  // 画像ファイルの読み込み
document.body.appendChild(img);  // 画像を表示

上記3行のコードで、画像を読み込んで表示させることが出来ます。

「img.src」に画像のパスを代入した時点で、ファイルの読み込みが自動的に始まるわけですが、画像ファイルは容量が大きいものが多いので読み込み完了までにある程度の時間が必要です。

この現象は、DOMのツリー構造が完了するまで待たないといけなかったケースとよく似ていると言えます。

例えば、読み込んだ画像の「幅サイズ」を取得するためのメソッドに「img.width」がありますが、次のように書いてしまうと取得することができません。

var img = new Image();

img.src = 'image/sample.jpg';

// 画像の「幅サイズ」を出力
console.log(img.width);

document.body.appendChild(img);

上記コードの場合、コンソールログに出力されるのは「0」になります。つまり、幅サイズを取得できていないということになります。

これは、「img.src」に画像のパスが代入されて読み込みが開始されているものの、まだ読み込みが完了していないうちに「img.width」が実行されているので、正確なサイズが取得できていないことになります。

これを解消するには、やはり「onloadイベント」が必要になってくるわけですね。

onloadイベントを使ってみよう!

DOMを扱った時と同じように、画像を扱う場合でも「onloadイベント」を使うことができます。

基本的な使い方は次のとおりです!

var img = new Image();

img.onload = function() {

    // 画像の読み込みが完了した時に実行する処理

};

img.src = 'image/sample.jpg';

このように、「img.onload」を使うことで、意図的に読み込みが完了した時の処理を書くことが出来るわけです。

先ほどの「img.width」による幅サイズの取得は、次のように書けば上手く実行されます。

var img = new Image();

img.onload = function() {

    // 画像の幅サイズを出力
    console.log(img.width);

};

img.src = 'image/sample.jpg';
document.body.appendChild(img);

このように書くことで、コンソールログには画像の幅サイズがしっかりと出力できるわけです。

ちなみに、「img.onload」も関数を代入するという性質上、複数書いた場合に上書きされるため、「addEventListener」を使った書き方にすることも可能です!

var img = new Image();

img.addEventListener('load', function {

    // 画像の幅サイズを出力
    console.log(img.width);

};

img.src = 'image/sample.jpg';
document.body.appendChild(img);

上記の画像ファイルの読み込みの他にもExcelやCSVファイルの読み込みやJSONファイルと呼ばれるプログラムで処理しやすいように加工されたファイルを読み込むなど、様々なファイルを読み込むケースがあると思います。

そのような方法については以下の記事で詳しく紹介していますので、ぜひ参考にしてください。

JavaScriptでファイル処理! JSONやCSVなどのファイルを読み込もう
更新日 : 2019年4月16日

実はonloadイベントの逆パターンもある!

これまで、さまざまな「onloadイベント」について学習してきました。

このイベントは、基本的に「何らかの処理を待つ」ことで、実行タイミングを調整していたわけですが、逆に「何らかの処理に移行」しようとした時に実行するイベントも用意されているのでご紹介しておきます!

これは主に、Webページをリロードする際や、別のURLに遷移する時などに実行されるイベントで、離脱防止や誤ってリロードするのを防止するような目的で使われることが多いでしょう。

「onbeforeunload」の使い方について

まずは基本的な書き方について見ていきたいのですが、利用するのは「onbeforeunload」と呼ばれるイベント処理です。

一般的な使い方としては、これまでの「onloadイベント」とまったく同じで、書き方も2種類あります。

// 1つ目の書き方
window.onbeforeunload = function(e) {

    // 実行したい処理を書く

}


// 2つ目の書き方
window.addEventListener('beforeunload', function(e) {

    // 実行したい処理を書く

});

「onbeforeunload」は、Webページの離脱防止に使われることから、次のように書くことで「メッセージダイアログ」をポップアップ表示することができます。

window.addEventListener('beforeunload', function(e) {

    // メッセージを表示する
    e.returnValue = '本当にページ移動しますか?';

});

ただし、一部のブラウザは固定のメッセージのみ表示されるようになっています。

メッセージ表示例
javascript-onload-tutorial-04

jQueryのreadyとloadの違いと使い方

ページの読み込み時に処理を行うには、jQueryの「ready」と「load」を使う方法もあります。

jQueryのreadyとloadの違いと使い方についてはこちらの記事で詳しく解説しているので、ぜひ確認してください。

【jQuery入門】ready(load)の使い方とHTMLの読み込み方法!
更新日 : 2019年5月30日

まとめ

今回はJavaScriptの実行タイミングについて、主に「onloadイベント」に潜むいくつかの罠をまとめて紹介いたしました。

簡単にもう一度まとめるとこうなります!

  • DOMのレンダリング前にJavaScriptを実行しない
  • window.onloadは上書きされることに注意する
  • 「DOMContentLoaded」でさらに素早く実行できる
  • DOMと同じく画像ファイルも読み込み完了までに時間がかかる
  • 「onbeforeunload」は「リロード・画面遷移」の時に実行できる


これらは決して難しい内容ではないうえ、知っているとWeb開発をさらに効率よく進められる要素でもあるので、ぜひこの機会にマスターしておきましょう!

LINEで送る
Pocket

無料でSEからWebエンジニアへ転職しませんか?



侍エンジニア塾では、完全未経験の方から現在SEだけどプログラミングはやっていないという経験者まで、幅広い方々の人生を好転させるプログラミング指導を行ってきました。SEの方とお話していくなかで、

  • システムエンジニアという職業だけどコードが書けない
  • 事務作業が多くスキルがないため将来が不安
  • スクールに通うと完全未経験者と同じスタートになるからレベルが合わない
という、すでに知識があるSEならではのお悩みがあることに気づきました。そんな方におすすめなのが、弊社の「転職コース 」です。

弊社では、マンツーマンでレッスンを行いますので、現在お持ちの知識レベルからカリキュラムを作成いたします。さらにこちらの転職コースは無料で受講を始められて転職成功でそのまま卒業できるというとてもお得なコースとなっています。

既に知識のあるSEといっても転職は年齢が若いほど受かりやすいため、まずは無料体験レッスンで今の現状や理想の働き方について一緒に考えていきましょう。

まずは無料体験レッスンを予約する

書いた人

マサト

マサト

JavaScriptが大好きで、趣味も仕事もJavaScriptを中心に活動していたら、いつの間にかフリーランスになってました。
30代になってからプログラミングを始めた経緯があり、分からないことだらけだった経験を踏まえて、読者に分かりやすい記事制作をモットーにしています。
JavaScript以外の趣味は、旅をしながらの街歩きや登山など。

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説