なかなか気になるタイトルの動画が出てたので。
こういうコード、ほんとに懐かしいな・・・w
// コレとか $(() => {}); // コレとか document.addEventListener("DOMContentLoaded", () => {}, false);
これまではめちゃめちゃよく使われてきたけど、実はよろしくないよっていう話。
TL;DR
- あるあるコードの問題
- `bundle.js`内で、DCLを待って処理するようにしてた場合
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css" /> <script src="bundle.js"></script> </head> <body> <div id="app"></div> </body> </html>
// bundle.js document.addEventListener("DOMContentLoaded", () => { // 処理... }, false);
- コードが運用されるにつれ、こう改修されるかもしれない
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css" /> <script src="bundle.js"></script> </head> <body> <div id="app"></div> <!-- ↓追加したよ --> <script defer src="https://cdn.example.com/analytics.js"></script> </body> </html>
- こんな風に3rdの`defer`なスクリプトが追加されたりするとどうなるか
- メインで実行すべきコード(DCL)がどんどん後回しになる
- どうすればいいか?
- DCLを待つのをやめて、`bundle.js`にも`defer`をつけるのがよい
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css" /> <script defer src="bundle.js"></script> </head> <body> <div id="app"></div> <script defer src="https://cdn.example.com/analytics.js"></script> </body> </html>
// bundle.js // 処理...
- 基本的にはコレでよい
DOMContentLoadedへの道のり
- ブラウザのしくみとして、ページがパースされていくにつれ、何が起きるか
- 1: `readyState: interactive`
- 2: 既存のstyle(media matches含む)の処理
- 3: `defer`な`script`すべてを順番に実行
- 4: `DOMContentLoaded`イベント発火
- 5: `readyState: complete`
- 6: `load`イベント発火
- 7: `pageshow`イベント発火
- こうしてみると、`DOMContentLoaded`とは?という感もある
- なので基本的に`defer`を使えばよい
- `type=module`にすれば、デフォルトで`defer`になる
- 記述された順に実行されるので、依存ライブラリなどは先に
deferのこれまで
- 1997年にIE4にはいった
- しかしバグがあって、複数のdeferの実行順序が変わるケースがあった・・・
- 2012年のIE10までバグってた・・・
asyncもあるよ
- いつでも`defer`でいいわけではない
- `async`のほうがいいときもある
- 3rdのスクリプトのように優先度が低いもの
- 単体で完結するようなもの
- `defer`みたく読み込み順を待つ必要がないもの
- `async`で、その実行タイミングをブラウザに任せてしまう
- 優先度を上げたいならpreloadするとか
- 本当に必要だったのは特定の要素がreadyかどうかのはず
- 例えばWebComponentsで書けば、`connectedCallback`が使える
- ただし、`innerHTML`みたいに子要素を使って何かしたい場合、`async`では不都合が起きるかもしれない
- `async`なスクリプトが実行されるタイミングで、子要素がちゃんと存在する保証がないから
- 親はあるので、親要素に対して動作するWebComponentsを書くというテクもある
- `MutationObserver`も使える
- DOMのアップデートを検知できるので、それで特定の要素の存在を検知する
というわけで、`defer`を啓蒙する動画でした!