HTML5Experts.jp

Navigation Timingだからできる、Webアプリを俯瞰したパフォーマンス計測(3/3)

いよいよHTMLドキュメントのダウンロードと、画面上への表示です。この動作の仕組みから、TATの「終了」がいつなのかを追ってみましょう。「終了」についてはかなり奥が深く、Web標準でもそのプロセスを「The End」として定義はしていますが、それだけでは語りきれない難しさがあります。

4. TCP接続、5. HTTPリクエスト/レスポンス

名前解決で得られたIPアドレスを使って、HTMLドキュメントが置かれたサーバへ「4. TCP接続」します。いわゆる、3ウェイハンドシェークというものです。サーバとの接続交渉が終わると、HTTPリクエストをサーバへ送信し、HTTPレスポンスを受け取ります。

HTTPレスポンスの結果からリダイレクトであることが発覚した場合、「2. キャッシュ確認」からやり直しです。この、リダイレクト動作にかかった時間もNavigation Timingでは取得でき、「redirectStart」「redirectEnd」の各プロパティを通じて取得することができます。

HTTPレスポンスから得られたデータは、いったん蓄積され、この後のDOMの生成で利用されることになります。

6. DOM生成

さて、ここからがブラウザの一番の見せ場、サーバから受信したHTMLドキュメントからDOMを生成し、描画を行うフェーズです。

HTML5のスペック「8.2章 Parsing HTML documents」に内部的な動作が定義されており、これに従い計測値が取得されます。このフェーズで意識すべきなのが、「①. HTMLドキュメント自体の読み込みを行っている段階(domLoading)」と「②. HTMLドキュメントの読み込みが完了し非同期に取得できる画像などのリソースを読み込んでいる段階(domInteractive)」の、2段階のステージです。

1段回目、domLoadingの段階。HTMLドキュメントの読み込みには、8KBというマジックナンバーが隠されています。これは、ブラウザがHTMLドキュメントの内容をパースする際に、一括で読み込みを行う単位と考えると良いでしょう。ブラウザはサーバから受信したHTMLドキュメントを、8KBずつ逐次パースし、DOM Contentを作っていきます。

JavaScript/CSSのような即時で反映する必要があるファイルの参照があった場合、HTMLドキュメントの受信は継続しますが、HTMLパース処理は停止し、JavaScript/CSSのコンパイルと実行を優先します。

DOM Contentの生成が終わった状態を、HTML5のスペックでは「interactive」と定義しています。JavaScriptにて「DOMContentLoadedイベント」を登録していた場合は、このタイミングで発火します。

7. リソース読み込み

ここからは、2段階目の説明に入ります。HTMLドキュメントが全て読み込まれ、画像などの非同期で読み込めるリソースを読み込んでいる段階です。先ほども説明しましたが、Web標準ではこの段階のことをinteractive(対話可能)と呼んでおり、名前の通り、画像の読み込み完了を待たずしてユーザからの入力を受付けることができます。

実は、ブラウザはHTMLドキュメントを読み込みつつリアルタイムに画面上へ表示する(ChromeはHTMLドキュメントのダウンロード完了時に表示する)という実装なため、「6. DOM生成」の段階でも既に入力可能だったりします。どちらをTATの開始と呼ぶべきか、非常に悩ましいところです。

画像の読み込みが完了し、Webページが完成したタイミングで「complete」という状態に推移します。completeへ推移すると、JavaScriptのloadイベントが発火します。ここで再び、ブラウザはJavaScriptの処理を動かすために、入力をブロックさせたりします。場合によっては、この段階でユーザからの入力を受け付けるために必要な、初期化処理を行なったりもします。例えば、jQueryの有名なプラグインであるDatePickerなんかは、loadイベント内で設定することが多く、ここに来るまでフォーカスを当ててもカレンダが表示されません。interactiveなんて言われていますが、実際にはloadイベントを実行するまではTATの終了とは言えないような気もしますね。ここまでくると、もはや終了の概念そのものをどう定義すべきかが、だんだんわからなくなってきました。

loadイベントの処理が完了すると、Navigation Timingで計測できる全ての処理が完了です。

なお、ここまでの過程で、JavaScriptやCSS、画像などの外部ファイルの読み込みを行っていますが、これら単独リソースごとの性能計測は、Web標準として少し扱いが異なります。詳しくは、「Resource Timing」を参照すると良いでしょう。

何をもってTATとするか?

ブラウザの仕組みについて一通り紹介したところで、TATを構成する要素が以下に分類できることが理解頂けたでしょう。この中のどこかに開始を作り、どこかに終了を作れば、あなたの求めるTATになるはずです!

開始候補、終了候補、なんて言葉を使ってみましたが、ここまでくるともはや、TATを取得することに意味があるのか?なんて思われても仕方ありません。実際のところ本当にその通りで、TATだけをピンポイントで取得しても、あまり役に立たなかったりします。

Navigation Timingはそもそも、ナビゲーションの動作の中から、性能のボトルネックを探すためのものです。生きた計測値を得るためのものです。ブラウザはナビゲーションを開始すると、様々なキャッシュを駆使して最小限で動作することを追求し、そして終了に向けて、DOM生成やリソースの取得、JavaScriptの初期実行を行い、最大限のポテンシャルを発揮しようとします。こうしたブラウザのメカニズムの中から、ボトルネックを探さなくてはいけないのですから、Navigation TimingはWebページの特性に合わせて、有用な情報を拾えるようにしなくてはいけません。

リソースの取得については「Resource Timing」、JavaScriptの性能に影響を与えるような処理に対しては、「High Resolution Time」のnow()なんかを利用して、計測を行うことが求められるでしょう。

パフォーマンスの改善は、まさに総合競技です。JavaScriptやCSS単独の高速化手法だけ知っててもダメだし、DBのパラメータチューニングだけできてもダメです。JavaやASP.NETやRuby On Railsも、全体から見ればほんの一部でしかありません。DNSやWebサーバ、APミドルなどのインフラも重要な構成要素ですし、私のようにイントラ向けのシステム開発を行なっている方はネットワーク装置の一台まで面倒を見ていることもあるでしょう。最近はクラウドも絡んできたりして、バックプレーンを共有する他社のWebアプリが性能に影響を与えるなんてのも聞いたことがあります。複雑化が進んでおり、ますます全体を見る目が求められているように思えます。

ところが、パフォーマンスの問題にぶつかると、どうしても自分の専門分野で見てしまい、DBだけを良くしようとしたり、JavaScriptだけを高速化しようと先走ってしまうことがあります。

Navigation Timingを入り口にして、生の測定値に基づき分析し、ブレークダウンしてみて下さい。きっとそれは、改善の近道となり、費用対効果の高い手段を見つけるヒントとなるでしょう。そしてWebアプリは、最高のパフォーマンスを得ることができるはずです。