load関数の中身が動作しない時はこれを読んでほしい（JSの実行タイミングのはなし）

[Ateam Lifestyle Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ateam-lifestyle)の17日目は、株式会社エイチームライフスタイルの @ryosuketter が担当します。

# はじめに

本記事は、JavaScriptとjQueryを使用した場合のブラウザレンダリングの順序に関する内容を書いています。

「何を今さら、jQuery」と言うご意見もあるかもしれませんが、実際の現場では、jQueryを使うことで素早く実装できるシーンもあるため、現在も少なからず使われています。手軽に使えるjQueryではありますが、正しい理解していないとハマってしまうかもしれない内容でしたので、今回は備忘録として残しておきました。

# 問題

ある実装を完成させ、検証したら、Internet Explorer（IE）だけ、`$(window).on (‘load’)`の中に書いてあるスクリプトが読み込まれておらず、アタフタしてしまいました。

問題の1つは、自分が、jQueryの下のやつを無意識で使っていたことが原因でした。

```js
$(function(){
  // ここにプログラムを記述
});
```

この記述は、jQueryでよく見かけるおまじない、ではなくて、ちゃんと意味があります。これは、「HTMLを読み込んでから処理を実行する」という意味で、画像などを除いて、HTML（DOM）の読み込みが終わったら、関数の中のスクリプトを実行するという意味です。

基本、jQueryはDOMを操作するための言語なので、それが全部読み込まれていないまま処理を実行すると正しく動作しない可能性があるので、大抵、上記の記述をまず書きます。自分は、無意識に書いていたので、ハマってしまいました。

## ページ読み込み時のJavaScriptの実行タイミング

- ページの読み込みが始まる
- HTML（DOM）の読み込みが終わる
- `$(function(){ ここのプログラムが実行される });` ← いわゆる`document-ready`
- 画像や動画など含めすべてのページにあるリソースが完全に読み込まれる
- `$(window).on('load', function(){ここのプログラムが実行される });`

# ハマった原因

自分はなんでハマったかとおいうと、下記のような記述をしてしまったからです。

```js
$(function(){
  // htmlロード時の処理
  $(window).on('load', function(){
    // ページ全体のリソースが読み込まれた時の処理
  });
});
```

つまり、`ready`関数と`load`関数の処理の実行タイミング理解が曖昧だったのが原因ですね。

```js:ready関数
$(function(){
  // htmlロード時の処理
});
```

```js:load関数
$(window).on('load', function(){
  // ページ全体のリソースが読み込まれた時の処理
});
```


おそらく、HTML（DOM）の読み込みが終わって、中身を読み込む時に、画像などの読み込みが完了しておらず、ready関数（`$(function(){ ここのプログラムが実行される });`）を出てしまい、実行されず終わってしまったのが原因かと思います。

ちなみに、これがjQuery2系だったら実行されていたかもしれませんが、自分は3系を使っていたので実行されませんでした。なぜなら、3系から、documentがreadyかどうかにかかわらず、処理の順序の一貫性を保証するようになったからです。

https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous

## $(document).readyの中身

$(document).readyの中身を[github](https://github.com/jquery/jquery/blob/master/src/core/ready.js)にある、jQueryの中身（実態はJS）を見てみましょう。

https://github.com/jquery/jquery/blob/master/src/core/ready.js

一部、自分には難しい記述もありましたが、今回関係するのは、以下の記述ですね（下の方にあります）。

```js
document.addEventListener( "DOMContentLoaded", completed );
```

これを見ると、`DOMContentLoaded`というイベントが発火したタイミングで、ready関数は実行されるようです。

### DOMContentLoadedとは

MDNを見ると

> The DOMContentLoaded event fires when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.

[Window: DOMContentLoaded event \- Web APIs \| MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event)

これより、ready関数は、CSSや画像ファイルの読み込みを待たず実行していることが分かりますね。また、jQueryに限らず、新しいバージョンを使用する際は変更点をしっかり把握していないといけませんね。

# 参考

- [jQuery Core 3.0 Upgrade Guide](https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous)
- [Window: DOMContentLoaded event \- Web APIs \| MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event)
- [IEでjQueryのwindow loadが動かない \| 月間ぬにふちさか](http://nunifuchisaka.com/archives/245)

# まとめ

[Ateam Lifestyle Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ateam-lifestyle)の18日目は、 @seira さんがお送りします。

“挑戦”を大事にするエイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
https://www.a-tm.co.jp/recruit/