無趣味の戯言

📄️

【JS】onloadイベントは思ったより後から来る

こんにちは、だいちゃんです。

Javascriptの書き方でちょっと詰まったところがあったのでメモしておきます。そんな基礎も知らずに!って感じかもしれませんがお手柔らかに...。

発火タイミングの種類

Javascriptで処理を実行させる場合、大きく分けてページ読み込みの「前」「直後」「完了後」の3つに分けられます。

それぞれに用途があるので、処理の内容や対象に合わせて使い分けられるようにしたいです。

ページ読み込みの「前」

HTMLは(というかプログラムは)基本的に上から順番に処理をしていくので、HTMLの head 要素内に直接書くか、jsファイルを読み込ませるなどすれば、 body を処理する前に実行させることができます。

注意点は、 HTMLの描画(パース)の邪魔になってしまう(=同期的読み込み) ことです。Javascriptのダウンロード・処理が終わるまで、HTMLのパースは一時停止されてしまいます。

下記のように、 async 属性を与えると、非同期で読み込んでくれる ので、HTMLのパースと並行してJavascriptのダウンロードが可能になります。ただ ダウンロードが終了するとそのタイミングでHTMLのパースを一時停止させ、Javascriptの処理行われる という点には注意が必要です。また、 async 属性をもつ要素が複数あった場合、処理の順番はダウンロードが終わった順になるので、 意図せぬ順番で実行されてしまう可能性もあります。

<script src="./script.js" async>

例えば、jQueryの本体の読み込みと、それに依存したJavascriptファイルの読み込みを両方 async で行うと実行できない可能性があるので、その場合はjQuery本体にはasyncを付けないデフォルトのままで読み込ませる方がいいかもしれません。

ページ読み込みの「直後」

ウェブページ(HTML)の読み込みが終わった直後のタイミングで処理されます。この場合、 画像などのダウンロードが追いついてなくても実行される ので、画像に対しての処理などには利用できません。

プログラムの特性を利用して、 body の終了タグ直前にJavascriptの処理(or 読み込みの記述)を書くと、ページの骨格部分が読み込み終わるタイミングで処理を実行させることができます。

また、Javascriptの記述位置ではなく、ソース上で発火タイミングを明示したい場合は、下記のように記述します。1つのJSファイル内で処理ごとに発火タイミングを変えたい時や、ソースを読む人に齟齬無く発火タイミングを伝えたいときに有用かな、と思います。

document.addEventListener("DOMContentLoaded", function() {
   // 実行したい処理
});

注意点は、 DOMContentLoaded イベントはIE8以前が非対応らしいです。さすがにそこまでサポートすることはもう無いと思いますが...w

ちなみに、 DOMContentLoaded よりちょっと先に実行させる場合、下記のように defer 属性を付けて記述します( head 内に書くべきだと思います)。特徴として、ダウンロードはHTMLのパースを待たずに非同期で行われます。また、 defer 属性がついた要素が複数ある場合はより上に記述されているものから順に処理されていきます。

<script src="./script.js" defer>

ページ読み込みの「完了後」

「直後」との違いは、 HTMLの読み込みが済んだだけでなく、画像など他のリソースも全てダウンロードしパースが完了したタイミングで実行される点 です。

window.onload = function() {
   // 実行したい処理
}

ハマりポイント

今回ハマったポイントは、onloadイベントで書いていたせいで、スライダーの初期化を画面サイズに応じてしたりしなかったりする処理が、画像の読み込みが完全に終わるまで実行されず、崩れたままになってしまっていました。

そもそもスライダーが初期化されなくても崩れないようにスタイルを与えておくべきだったかもしれませんが、テストサーバーでは崩れることが無く気にもしませんでした。本番サーバーが少し重かったみたいで、本番公開後に気付いてしまいました...。

デバイスや通信環境、サーバーの負荷具合によって読み込み速度は変わりますし、比較的重たい画像の完全ダウンロードを待っていると処理内容によっては見た目や動作に影響を及ぼす可能性があるので今後注意していきたいです。 HTMLを読み込む前に処理しないといけないか?骨組み(DOM)の解析が終わったタイミングがベストか?他のJSファイルに依存していないか(実行順序が重要でないか)?画像など比較的重たい要素に対する処理か?などを軸に検討していくべきかもしれません。


そういえば ポートフォリオサイト のローディング画面もonloadでフェードアウトさせているので、モバイル環境だとローディング画面が長めに表示されてしまっています(汗)

意図としては、Webフォントの読み込みなどもあるのでonloadがいいかな〜って思ってたのですが、そこまでガチガチにしなくてもいいかもしれませんね。もしくはonloadにしたまま、画像をlazyloadとかにしても良さそうです。 次回リニューアルの際に検討しようと思います!

Buy Me A Coffee