記事内に広告が含まれています

【ワレコのWEBプログラミング】window.onload $(document).ready $(window).on(‘load’ 【実行順序】

この記事は約16分で読めます。
スポンサーリンク
ワレコ
ワレコ

WEBプログラミングではページがロードされた時に何らかの処理を最初に実行したい状況は良くある。

ところがページロード時の処理の呼び出し方が色々あるのでややこしいのだ。

具体的にはJavaScriptやjQuery関連の解説サイトを見ていると、以下のような色んな手法が有ることが分かる。

●JavaScript方式
window.onload = function() {...};
window.onload = () => ...;
window.addEventListener("load", () => ...);
document.addEventListener("DOMContentLoaded", function () {...})

●jQuery方式
$(document).ready
$(window).on('load'

これらの実行順序についての解説も沢山見かける。

今日、ワテもある簡単なJavaScriptプログラムを書いていてこれらの関数で少々混乱した。

以下、その備忘録。

スポンサーリンク
スポンサーリンク

ページロード時に実行される各種関数の違い

ワテが最初に覚えたのは以下のようなwindow.onloadのやつだ。

//通常関数版
window.onload = function() { 
	console.log("成功!");
};

//アロー関数(arrow function)版
window.onload = (event) => {
	console.log("アロー関数版");
};

window.onload を使うと「ページが完全に読み込まれた後に実行される」と言う動作になる。

同じく、window.addEventListener(“load”というやつもある。

//通常関数版
window.addEventListener("load", function () {
	console.log("ページが完全に読み込まれました。");
});
//アロー関数版
window.addEventListener("load", (event) => {
	console.log("ページが完全に読み込まれました。");
});

このwindow.addEventListener(“load”も先程のwindow.onloadと同じく「ページが完全に読み込まれた後に実行される」と言う動作になるが、両者の挙動は若干異なる。それはこの後で紹介する。

次にdocument.addEventListener(“DOMContentLoaded”と言うのもある。

//通常関数版
document.addEventListener("DOMContentLoaded", function () {
	console.log("DOMが完全にロードされた。");
});

//アロー関数版
document.addEventListener("DOMContentLoaded", (event) => {
	console.log("DOMが完全にロードされた。");
});

//これでも間違いではない
window.addEventListener("DOMContentLoaded", (event) => {
	console.log("DOMが完全にロードされた。");
});

DOMContentLoadedを使うとページのHTML構造だけが読み込まれた段階で発火するため、画像やCSSの読み込みが完了していなくても動作する。そのために意図したタイミングを外してしまう恐れもあるので要注意だ。

なお、

window.addEventListener("DOMContentLoaded", ...);

でも間違いではないが、通常は

document.addEventListener("DOMContentLoaded", ...);

を使うのが一般的だ。

なぜなら DOMContentLoaded は document の読み込みが完了したタイミング で発火するイベントだからだ。
windowにバインドしても動作に大きな違いはないが、理論的には document に登録するほうが適切だと思われるので。

window.onload が二つ以上あると最後のやつしか実行されない

さて、window.onloadを使う場合の注意事項を説明しておこう。

ワテのブログでは幾つかのページにJavaScriptのサンプルプログラムが動くようにしている。

例えば以下の二つの記事に埋め込んでいるサンプルプログラムだ。

【ワレコの講座】JavaScriptのPromiseを多段連結する【これは便利】
このところ、JavaScriptやTypeScriptのPromiseを猛烈に勉強中だ。完了までに数秒掛かる非同期処理1があり、それが成功したら同じく数秒掛かる非同期処理2を実行したい。それが成功したら、同じく数秒掛かる非同期処理3を実行し...
【ワレコの講座】JavaScriptでSetTimeoutを使って他の処理が終わったかどうか調べる
JavaScriptは奥が深い。約1年くらい使ってきたが、ワテの知らない機能がまだまだ沢山あるようだ。今回のテーマは、「JavaScriptでSetTimeoutを使って他の処理が終わったかどうか調べる」だ。例えば、JavaScriptでプ...

これらのサンプルプログラムはWordPressのカスタムフィールドに自作のJavaScriptプログラムのコードを埋め込むことで動作するようにしている。

そのコードはページが読み込まれた時点で実行したいので、コードの冒頭ではwindow.onload を使っている。

今までそれで問題無く動いていたのだが、今日、上記の記事内に埋め込んでいるサンプルプログラムが動いていない事に気づいた。

良く調べてみると、数日前の改良でそれらとは別のプログラムをページに追加したのだがそこでもwindow.onload を使っていた。

その改良とはこれだ。

【ワテのオープンソース】ハイライト表示プラグインhighlight.jsを拡張する【表示幅を広げる】
ワテの場合、このWordPressのブログ記事は2015年8月から開始したので今日で約一年くらい経った。ブログの内容は、主に プログラミング関連記事 世界情勢、政治、経済、金融に関する専門家(自称)としてのコメント 日常の出来事のくだらない...

なぜJavaScriptプログラムが動作しなくなったのかを必死でネットを検索して判明したのは、window.onload は二つ以上あっても最後のやつしか動かないと言う事実だ。

window.onload = function() {
	console.log("処理A");	//こちらは実行されない。
};

window.onload = function() {
	console.log("処理B");	//こちらだけが実行される。
};

つまり上のコードのように複数のwindow.onloadを実行した場合には、window.onload に設定したハンドラが上書きされる可能性があり、最後のハンドラだけが実行されるという挙動になるのだ。

要するに window.onload= と言う代入文の形式なので、代入を繰り返すと上書きされると言う事だ。その結果、最後に代入した処理が実行されると言う事になる。

window.addEventListener(“load”, … );を使うのが無難

一方、window.addEventListener(“load”, … ) なら複数を実行しても、全て実行される。

window.addEventListener("load", function() {
	console.log("処理A");
});

window.addEventListener("load", function() {
	console.log("処理B");
});

要するに window.addEventListener(“load”, の場合なら、それはイベントリスナーをadd(追加)しているので、複数のイベントリスナーをドンドン追加して行くことが出来る仕様になっているのだろう。

なので、ワテの場合は通常はページロード時に最初に何らかの処理をやりたい場合には、 window.addEventListener(“load”, … ) を使うようにしている。

JavaScriptとjQueryのload, ready関数の実行順序の調査

今回のwindow.loadが複数有っても最後のやつしか実行されないトラブル調査の過程で、それ以外の各種のイベントハンドラーの実行順序を調査してみた。

window.onload, $(document).ready, $(window).on(‘load’ の実行順序や複数定義の場合の挙動調査

まず試したのがよく見かけるwindow.onload $(document).ready $(window).on(‘load’ に付いても調査してみた。

以下のようなテストプログラムを即席で書いてみた。

ここで別の問題に気付いた。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script src="https://code.jquery.com/jquery-3.1.0.min.js"
            integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s="
            crossorigin="anonymous"></script>
    <!--<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>-->
    <!--<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>-->
    <!--<script src="Scripts/jquery-3.1.0.js"></script>-->
 
</head>
<body>
 
    <script type="text/javascript">
 
        //① jQueryの場合
 
        //chromeの場合にこの二つの実行順序は1➜2もあれば2➜1もあった。
        $(document).ready(function () {
            alert("$(document).ready( を使う1。");
        });
        $(document).ready(function () {
            alert("$(document).ready( を使う2。");
        });
 
        //②chromeで数回試したが、実行順序は1➜2のようだ
        $(window).on('load', function () {
            alert("$(window).on('load' を使う1。");
        });
        $(window).on('load', function () {
            alert("$(window).on('load' を使う2。");
        });
 
 
        //③ .load() はDeprecated(非推奨)なのだが、jquery-3.1.0.js では
        //
        //   jquery-3.1.0.js:9649 Uncaught TypeError: url.indexOf is not a function
        //
        //というエラーで動かなかったので、既に廃止されているのかな。
        if (false)
            $(window).load(function () {
                alert('$(window).load は廃止。今は動かない。');
            });
 
 
        //④ JavaScriptの場合
        window.onload = function () {
            alert('window.onload1 二つあるとこちらは実行されない。');
        }
        window.onload = function () {
            alert('window.onload2 二つあると最後のやつが実行される。');
        }
 
        // 全体の実行順序はchromeの場合には、以下のようになった。
        // $(window).on('load'
        // window.onload
        // $(document).ready
 
    </script>
 
</body>
</html>

その問題とは、

$(window).load(function () {   ...   })

がChromeでもIEでも動かない。

jquery-3.1.0.js:9649 Uncaught TypeError: url.indexOf is not a function

こんなエラーが出るのだ。

もう訳分からん。

でも、少し調べたら解決。

$(window).load(function () {   ...   })   非推奨(Deprecated)

$(window).on('load', function () {... }) こちらを使うと問題ない

と言う事だが、本日(2016/8/15)時点の最新の jquery-3.1.0.js では、非推奨な方式の .load() は動かないようだ。

従って、後者の .on(‘load’, を使って解決。

以下、ワテの実験で分かった幾つかの事実を紹介する。

$(document).ready が複数あると、実行順序は不定のようだ

$(document).ready(function () {  ...  });   // ①

$(document).ready(function () {  ...  });   // ②

のように二つを実行すると、両方実行出来たのだが、必ずしもこの①➜②の順番では実行されない。数回実験したが②➜①の場合もあった。

なお実験したのはChrome。他のIEやFirefoxでは未確認。

上記のサンプルプログラムをChromeとIEで実行してみたが、その実験結果では、以下のような実行順序となった。

JavaScriptとjQueryのload, ready関数の実行順序の調査結果

JavaScriptとjQueryのload, ready関数の実行順序を調査してみた。

その実験結果は以下のようになった。

$(window).on('load'	//複数あっても全部実行される

window.onload		//複数あると最後のやつが実行さる

$(document).ready	//複数あっても全部実行される。実行順はランダムに変わる。

ただし、本来

$(document).ready(function(){ ... });

は、HTML documentが読み込まれた時点で実行。

$(window).on('load', function() { ... });

は、その後でHTML documentだけでなく、ページ内でリンクが張られている全てのリソース(例えば画像、CSSスタイルなど)が読み込まれた時点で実行と言うふうに多くのブログサイトなどで説明されている。

しかし、今回のワテの実験では画像もCSSも無い簡素なページではこの規則通りには行かずに、先に on(‘load’ が実行され、次に ready が実行される場合も有る事が判明した。

要注意だ。

その理由は何だろうか?

推測するなら、恐らく、画像もCSSも無い簡素なページだと一瞬でページのhtmlテキストデータが読み込まれる訳だから、ready条件達成とload条件達成の判定がほぼ同時になるのかもしれない。

その結果、ブラウザーさんが混乱して間違うのかも知れない。

まとめ

ワレコ
ワレコ

当記事は数年前に執筆したものを本日改定したものです。

WEBプログラミングの世界は日進月歩なので新しい事をドンドン勉強しないと時代に取り残される。

ワテはJavaScript、jQueryを約一年くらいやって来た(現在は十年近くやっている)が、以下の沢山の手法の使い方は何回覚えても忘れる。

●JavaScript方式
window.onload = function() {...};
window.onload = () => ...;
window.addEventListener("load", () => ...); 
document.addEventListener("DOMContentLoaded", function () {...}) 

●jQuery方式 
$(window).on('load', function () { ... });
$(document).ready(function () { ... });

今回の収穫は以下の通り。

$(window).load(function () { ... });       // 非推奨(Deprecated)なので使わないようにする

$(window).on('load', function () { ... }); // もし使うならこちら

また、ページ読み込み時に実行したい処理は以下のどちらかを使っておけば良い。

$(window).on('load', function () { ... });

$(document).ready(function () { ... });

これらを使っておけば、もし誰か別の人が同じページで load や ready の処理を追加していてもかち合う事は無いと言う事だ。

重要な発見

さらに、この二つは全く同じ物。

$(function() { ... });
$(document).ready(function () { ... });
jQuery $(window).load not working as expected
I ran into an something that did not expect today when removing part of a function that previously was loaded in my asse...

らしい。知らなんだ。

最近のワテの記述スタイル

と言う事で、最近のワテの場合はHTMLページをロードした直後に実行したい処理は、以下の例のように書くようにしている。

<script>
   $(function(){ 
     ...  // ページをロードした直後に実行したい処理1 
   });

   $(function(){
     ...  // ページをロードした直後に実行したい処理2
   });
</script>

<script>
   $(function(){ 
     ...   // 必要なら<script>ブロックを複数入れても良い。処理3
   });
</script>

なお、複数の $(function(){ … }); を入れている場合には、どれが先に実行されるのかは恐らく保証されていないと思う。

ブラウザーによっても異なる可能性があるだろう。

なので、どっちが先に実行されても良いようにプログラムを書いておくと良いだろう。

より最近のワテのスタイル

あるいはjQueryを使わずにピュアなJavaScriptで書くならこんな感じか。

//通常関数版
window.addEventListener("load", function () {
	console.log("ページが完全に読み込まれました。");
});
//アロー関数版
window.addEventListener("load", (event) => {
	console.log("ページが完全に読み込まれました。");
});

ワテは、最近は専ら(もっぱら)この記法を採用している。

WEBプログラミングの本を読む

アマゾンでランキングの高い二冊を選んでみた。

スポンサーリンク
コメントを読む

この記事には読者の方からコメントが 2件あります。
興味ある人はこのページ下部にあるコメントを参照下さい。

JavaScriptjQuery
スポンサーリンク
シェアする
warekoをフォローする
スポンサーリンク

コメント

  1. 風吹けば名無し より:

    素晴らしい記事をありがとうございます!

    • wareko より:

      風吹けば名無し様
      この度は小生の記事にコメント有難うございました。
      数年前まではWEBプログラミングに熱中していて、その当時jQueryやJavaScriptを独学していて色々と実験しました。
      この記事で紹介した内容は、ブラウザーの種類やバージョン、jQueryのバージョンなどでも変わると思いますので、必ずしも最新の情報ではありません。
      ですので、もし必要なら記事で紹介しているhtmlサンプルなどを参考にして頂きまして、最新状況をお試しください。