JavaScriptの外部ファイル読み込みでasyncやdeferが不要な場合
巷ではWEBページの高速化のためJavaScriptの外部ファイルを読む込む時に、asyncやdeferをつけるといいと説明されています。Googleのanalyticsやadsense、各種SNSシェアボタンにもついてます。
ですが当然、下手にasyncやdeferをつけないほうがいいケースというのもある。じゃあそれはいつなの?
要は描写に直接関わる部分、何よりも先に読み込まれてほしい場合です。htmlより先に読まれて欲しいなんて、そんなことあるのかいと思っていたのですがありました。
知っている人に取ってみれば当たり前過ぎて反吐が出そうな話だと思います。でも知らない人間にとっては未だ不透明な部分が多いと言うとか、はっきりとした使い分けのボーダーラインがよくわからない感じです。今後1つ1つ潰していきたいと思っているところであります。
ページのド頭で読み込まれて実行されてほしい場合
このサイトには、真ん中に左右のウインドウサイズを変えるための「バー」を設置してあります。「阿部寛公式ホームページ的な昔なつかしのframeset風レイアウト」を作ってみたくてこうしました。バーをドラッグすれば左右のウインドウサイズが変わるのです。
そして、どうせならページ遷移した後もドラッグして変えたサイズを維持したい。そんなときはJavaScriptの出番です。
左右それぞれのウインドウサイズをcookieやlocalStorage、あるいはsessionStorageに保存しておき、次にページが読み込まれるタイミングで呼び出します。
そうすればあたかもSPA(Single Page Application)かのようにウインドウサイズが維持されたままページが切り替わってくれる、そんな段取りです。
/*
* バーを動かして変更したサイズをセッションストレージに保存。
* ページ読み込み時に値を呼び出してスタイルに適用
*/
if (sessionStorage.getItem('k')) {
var style = document.createElement('style');
var item = sessionStorage.getItem('k');
style.textContent = item;
document.head.appendChild(style);
}
ページが読み込まれてから要素のwidthやleftを element.style.width などでいじる方法も試みたのですが、後から読み込まれるadsenseに引っ張られて(?)勝手にサイズが変わることがあったのでhead内で<stlye></stlye>を新たに作って差し込む方法にしました。
そしてdeferやasyncが不要な状況がやってくる
これをうまいことやるにはasyncとかdeferが邪魔です。ないほうが良い。
「deferやasyncは速いらしい」と聞いてとりあえずつけてみたものの、見事に失敗しました。
最初に一瞬デフォルトのレイアウトで表示されてからババッと画面がチラついて前のページで記憶したウインドウサイズに移行するんです。
非同期で読み込んでしまうと待っていてほしい描写も進んでしまいます。その後にまたやり直すのですから二度手間です。
そしてこの一瞬のチラつき、非常に不快です。ampページの真っ白や画像遅延読み込みの真っ白と同じような感じでしょうか。走っていくるときに服を引っ張られるのと似たストレスを感じます。
二度手間になるくらいなら、DOMの読み込みを一旦止めて左右のウインドウサイズが確定してから描写をスタートしてもらったほうが結果的にストレスなくページを閲覧することができます。切り替わりの最初に空白があるのは経験からいって分かっていることですが、途中に空白を挟まれるのは直感に反していてなんか嫌な感じ、ということなのだと思います。
deferのために分けるか、一括で読み込んでしまうか。
調査段階。これから先調べるための補足メモ。
上で例に挙げた左右に分けたウインドウサイズ保存を実現する場合、最低2つの工程ができます。
1つはウインドウサイズを変えたときに値を保存する工程(ページ読み込み後でないと実行できない)。
もう1つは描写前にウインドウサイズを指定する工程(ページ描写前に実行する必要がある)。
2つを1つのファイルにまとめるか、分けるかという話。
まとめるなら、両方1つのファイルに記述してページ描写前に読み込んでしまう。
分けるなら、ページ読み込み後に実行するScriptはdeferを使い、ページ描写前に実行するScriptは当然何も記述せずに配置。
deferなしが速いのはどんな状況か?
このサイトに使われる自前のJavaScriptファイルは圧縮後1KBほどと非常に小さいです。このような場合はまとめて一気に冒頭でdeferなしに読み込んでしまったほうが良さげです。
HTTP/2で通信しているのであれば、deferも何も記述せずに黙って普通に良しなにやってもらったほうが速い、ということなのかもしれません。
1MBのJSONファイルならdefer効果てきめん
インクリメンタルサーチを実装したらJSONファイルが1MBくらいになりました。これくらいの大きさだとdeferによる非同期読み込みの効果は目に見えてわかります。
しかし当然ながら、検索窓が画面に表示されたところでJSONデータの読み込みが終わらないことには検索できないので結局終わるまで待たなければいけません。
先に表示されるのは確かに嬉しいですが、本当にただ閲覧できればそれで良いというページ出ない限り、さきに表示だけしてしまうことが必ずしもベストとは限らないのかなと思いました。
もっと色んなケースで検証したいと思います。
記事一覧へ戻る