Hatena::Groupsubtech

ういはるかぜの化学

Monday, December 09, 2013

サイトを先読みに対応させる 01:29 サイトを先読みに対応させる - ういはるかぜの化学 を含むブックマーク はてなブックマーク - サイトを先読みに対応させる - ういはるかぜの化学

このエントリーはInternet Explorer Advent Calendar 2013の9日目です。

今日は開発者向けのお話です。Internet Explorer 11から対応したGoogle Chromeなども以前から対応しているサイトの先読みの機能についての話です。

サイトの先読みって何?

そもそもサイトの先読みというのは現在表示しているページの先をあらかじめ読み込んでおくことでブラウジングの体感速度を上げる手法です。

例えば検索エンジンで検索結果の上位ページはクリックされる可能性が高いリンクです。つまり現在見ているページ(=検索結果)から遷移する先がある程度予想できます。ということは検索結果をユーザーが見ているうちにリンク先を裏側で読み込んでおけば検索結果からリンク先へ飛んだ際にすぐさま表示できるわけです。

例えばBing(英語版)だと検索結果の一番目のサイトを先読み/プリレンダリングするといったことが行われています。

f:id:mayuki:20131210012748p:image:w640

"Windows Azure"で検索した結果の一番目にポインターをホバーするとツールチップに「Preloading …」と出てきて先読みしていることがわかります。バックグラウンドでの先読みが完了していればクリックしての遷移がとても速くなります。

先読みの方法

リンク先をあらかじめ読み込んでおくと言ってもいくつか方法があります。Internet Explorer 11では以下の方法に対応しています。

DNS解決をあらかじめ行う(dns-prefetch)
DNSの名前解決をバックグラウンドで行うことで次に遷移するときにDNS解決の時間を短縮する
リソースを先読みする(prefetch)
リソースを先読みしてキャッシュに格納しておくことでリソースの読み込みを早くする
ページをプリレンダリングする(prerender)
ページ丸ごとバックグラウンドで読み込んでレンダリングしておくことで高速に遷移できるようにする(上のBingはこれです)

先読みの指示の仕方

先読みの方法が3つあることがわかったので実際にブラウザにどう指示すれば先読みしてくれるのか?というお話です。

DNS解決をあらかじめ行う(dns-prefetch)

DNS解決をあらかじめ行っておくこと(DNSプリフェッチ)で何が嬉しいかというと、リンク先に遷移しようとしたときやリソースを取得しようとしたときにはじめてDNS解決行われることによる無駄な時間を減らすことができます。

DNSプリフェッチをブラウザに指示するには以下のようなlink要素を記述します。

<link rel="dns-prefetch" href="http://www.example.com/" />

こうすることで www.example.comIPアドレスをあらかじめキャッシュするようになります。

リソースを先読みする(prefetch)

リソースの先読みは後から差し込まれる画像などを先読みしておくことでキャッシュしておくというものです。

リソースの先読みをブラウザに指示するには以下のようなlink要素を記述します。

<link rel="prefetch" href="http://www.example.com/" />
ページをプリレンダリングする(prerender)

ページのプリレンダリングはリソースのダウンロードに加えてレンダリングも完了させておくという先読みの中でも最強の先読みともいえます。

プリレンダリングしてほしい旨をブラウザに指示するには以下のようなlink要素を記述します。

<link rel="prerender" href="http://www.example.com/" />

実に簡単ですね。こうすると裏側で指定されたURLを取得してレンダリングします。

ちなみにInternet Explorer 11ではJavaScriptからlink要素を差し込んでも認識するようです(Bingはそうしてた)。

プリレンダリングの注意点と制限

プリレンダリングはバックグラウンドでレンダリングしておくという挙動のため単純な先読みよりもセンシティブな挙動となります。そのためいくつかの制限やページ制作の注意点があります。

なお前提としてプリレンダリングを指示する側のページでは一つのページしかプリレンダリングを指示できません。

実はPrerender and prefetch support (Windows)に書いてありますがざっと説明します。

プリレンダリングできる条件

指定されたURLのページがプリレンダリングできる条件として最低限以下のものを満たしている必要があります。

  • 従量制ネットワークの場合にはプランによって決まる(プランの詳細は謎。ConnectionCost.Conservativeだとダメとかかも)
  • 対象のURLがファイルのダウンロードとならないこと
  • 対象のURLhttp スキームまたは https スキームであること
  • 対象のURLはトップレベルのドキュメントであり、iframeではないこと
  • link要素を含むページが表示状態であり、フォアグラウンドなタブ(選択状態)であり最小化されていないこと
プリレンダリングが一時停止される場合

さらに以下の条件を満たさない場合にはレンダリングは途中で停止されます。つまり以下の条件に当たった瞬間にそこでプリレンダリングは一時停止するということのようです。

  • プリレンダリング対象のページ中で何らかのUI通知が発生した場合
    • alertやウィンドウを開いたり、何らかの通知が発生したり
  • プリレンダリング対象のページ中のvideo要素またはaudio要素でメディアが自動的に再生された場合
    • autoplay属性とか
  • プリレンダリング対象の履歴が変更される場合
    • window.historyが更新されるようなナビゲーションが発生したり
プリレンダリングされたページが破棄される場合

プリレンダリングされたページも以下のような特定の条件を満たすとその状態が破棄されます。

  • プリレンダリングしたページを5分以内に表示しなかった場合
  • ユーザーが別なページを開いた場合
  • ユーザーが別なタブに切り替えた場合
  • JavaScriptによって別なプリレンダリング対象を指定したlink要素が差し込まれた場合
  • プリレンダリング対象ページを読み込み中にエラー(404とか)が発生した場合
プリレンダリングによる副作用

プリレンダリングは裏側でページの実行が行われるのでいくつか副作用が発生します。特にJavaScriptによる処理が動いてしまうので注意が必要です。

  • ActiveX コントロールはユーザーがページを表示した瞬間に使えるようになる
    • そのためreadyStateで利用できるかどうか確認する
  • ページが表示されたときにアニメーションが動作しないことがある
    • プリレンダリング中にアニメーションが発動して完了してしまうと何も起きなくなる
  • タイマーが予期しない結果となることがある
    • 多分Interval通りにこないとかそういうこと
  • CookieやIndexedDB, Web Storageによるデータの保持はそのまま維持されます

ドキュメントにはloadまでに起こる問題といった書かれ方をしているので、ページのloadイベントまでは普通に実行されそこで一時停止するものと考えられます。

なのでDOMContentLoadedで行った処理はそのまま反映されてしまう可能性がありますので注意が必要です。

まとめ

ページの先読みはユーザーの行動を概ね予測できる場合にはとても強力に動作します。

ページのロードにかかる時間は当然同じわけですが、ユーザーのインタラクションを待ってから遷移するのと非同期でバックグラウンドで取りに行って用意しておくのでは体感には大きな差が出ますのでうまく使えば大変効果的ではないでしょうか。

トラックバック - http://subtech.g.hatena.ne.jp/mayuki/20131209