@CongHD (コン ホ)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Jqueryの「onload」と「ready」の呼ばれる順番はchromeとoperaが逆だ。

解決したいこと

edge,operaブラウザとchromeのJS呼ばれる順番は逆!

発生している問題・エラー

同じソースコードでopera(edgeはバージョンによる)とchromeのJS実行順番が逆です。

該当するソースコード

<body>
  
</body>
<script>
    $(window).on('load', function () {
        console.log("onload");
    });
    $(function () {  
      console.log("ready");
    });
</script>

自分で試したこと

Chromeの出たconsole.log:
image.png

operaの出たconsole.log:
image.png

原因が分かっている方がいらっしゃければ教えていただければ助かります
よろしくお願いします。

1 likes

2Answer

まず前提として、jQueryのreadyは「DOM(=HTML)の読み込みが完了した時」で、JSのloadは「DOM+コンテンツ(画像など)の読み込みが完了した時」に実行されます。
のでもしこのコードに大きな画像が埋め込まれていたら、その分loadが遅れるのでreadyが必ず先に実行されると思います。

JSのこの手のイベントは宣言時にすでに読み込みが完了していたらそのまますぐに実行し始めます。なのでいくつかのブラウザーではloadの到達時にはコンテンツを読み切ったと判断したのだと思います。
そういう意味ではloadreadyの宣言を逆にしたら同じ順番になる気配がします。また以下のようにscriptを先に書いたり、scriptのあとにもなにか書くだけで実行順が変わる可能性もあります。

<script></script>
<body></body>
<body></body>
<script></script>
<foot></foot>

このような処理の実行結果はブラウザやコードの状態によって簡単に変わります。イベント内の処理は自分の実行タイミングのみを気にするべきで、他のイベントが終了済みかどうかを気にしなければならないプログラムを作らないでください。その場合は違う非同期が必要です。

4Like

@CongHD さん
jQuery#ready はいくつか独自処理を行っており、DOMContentLoaded と完全な互換性はなかったと記憶しています。

また、DOMContentLoaded を使うのなら、リソース読み込み前のhead要素内あたりが妥当で、</body> 直前の位置でイベントハンドラ定義を行うと、リソース読み込みが既に終わっているので、コード上で即時実行する場合とほぼタイミングが変わりません。

<!DOCTYPE html>
<html lang='ja'>
<head>
	<meta charset='utf-8'>
	<title>sample</title>
	<script src="https://code.jquery.com/jquery-3.6.1.min.js"
		integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
	<script>
		'use strict';
		const handleEvent = event => console.log(event.type);
		jQuery(() => console.log('ready'));
		jQuery(document).on('DOMContentLoaded', handleEvent);
		jQuery(window).on('load', handleEvent);
	</script>
</head>
<body>
	<!-- 何らかの有効な外部リソース -->
	<img src="https://www.iana.org/_img/2022/iana-logo-header.svg" alt="iana" />
	<img src="https://qiita-user-profile-images.imgix.net/https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Ff412ddece0434f8d7e728726a5e7ce19?ixlib=rb-4.0.0&auto=compress%2Cformat&lossless=0&w=48&s=42e8d2493c650baff48e644f01be7e65" alt="@CongHD" />
	<img src="foo.jpg" alt="foo" />
	<img src="bar.jpg" alt="bar" />
</body>
</html>

上記HTMLをGoogle Chrome 106.0.5249.119で検証し、下記結果を確認しました。

  • 1回目 … DOMContentLoaded -> ready -> load
  • 2回目以降 … DOMContentLoaded -> load -> ready

個人的には jQuery.prototype.ready の独特の動きが好きではないのと、下記いずれかで解決可能なので、jQueryコードを読み解くのは止めたいと思います。

  • </body> 直前で即時実行
  • DOMCOntentLoaded イベントを利用

「jquery-3.6.1.js」の下記コードを解読すればわかると思うので、興味があればお調べください。

jQuery.fn.ready = function( fn ) {

	readyList
		.then( fn )

		// Wrap jQuery.readyException in a function so that the lookup
		// happens at the time of error handling instead of callback
		// registration.
		.catch( function( error ) {
			jQuery.readyException( error );
		} );

	return this;
};
2Like

Your answer might help someone💌