Webアプリのパフォーマンス改善と言えば、JavaScriptやDOMアクセスなど、既存の技術ベースな改善手法を想像する方も多いでしょう。最近では、こうした改善のあり方を、別の視点からもう少し広げようというアイデアが存在感を持ち始めています。それは「Web標準」です。
そこで今回、Web標準側でできるWebアプリのパフォーマンス改善について、掻い摘んで紹介します。全てを説明となるとキリがないので、キーワードを中心とさせて頂きます。最近になって、結構実用化が進んできているので、悩んだ時には試してみる価値はあるでしょう。
1. リソースを先に読み込む
linkタグにてURLなどを指定することで、これから先に読み込ませる可能性が高いWebページのリソースを予め読み込むWeb標準があります。ニュースサイトでは次のページを先読みしたり、ログイン画面を表示中にフレームワークの本体などのファイル容量の大きなスクリプトファイルを読み込むなど、柔軟なリソース操作でかなりのパフォーマンス改善が期待できます。
ここでは、3つの先読み技術を紹介します。
- prerender : 1つのページの全てのリソースを先読みする。
- prefetch : 単独リソースの先読み。JSファイルやimgファイルなど。
- dns-prefetch : DNSの名前解決の先読み。(※今のところはベンダ独自仕様)
▼ サンプルコード
<!-- 次のページの読み込み --> <link rel="prerender" href="./?page=2" /> <!-- 近いうちに必要になる大きいリソースの先読み --> <link rel="prefetch" href="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js" /> <!-- 近いうちに必要になるDNSの名前解決 --> <link rel="dns-prefetch" href="http://example.com/" />
上記は、iPhoneを除けばスマートデバイス(AndroidやWindows8.1)では既に実用段階に入っている点、実装されていないブラウザでは無視される点、フォールバックが難しいという点、パフォーマンスが劇的に改善されるという4つのポイントから、2014年はかなり広がりを見せると睨んでいます。
2. リソースの読み込み順序を操作する
「resource-priorities(ネットワークの優先順位付け)」は、CSSファイルやimgファイルなど、ロードが必要なリソースに対して、優先付けを行うためのWeb標準です。Webページを表示する際に、画面に表示されない箇所を後で読み込ませるといった活用方法があります。画像が多いようなページでは、初期表示のパフォーマンスを改善さることができるでしょう。ただ、そこそこ複雑性の高いページでないとその改善が見えてこないため、デバッグは苦労するかもしれません。
ステータスとしてはまだまだ議論中のワーキングドラフトという状況ですが、Chrome(安定しているかは不明)やIE(lazyloadのみ)では既に部分的な実装が始まっています。
- lazyload : 他のリソースよりも遅れて読み込む
- postpone : 画面上に表示されるまで読み込まない
▼ 例1:タグのプロパティから扱う場合
<img src="./img/hoge.png" lazyload /> <img src="./img/fuga.png" postpone />
▼ 例2:CSSから扱う場合
img.hoge { resource-priorities : lazy-load; } img.fuga { resource-priorities : postpone; }
▼ 例3:JavaScriptから扱う場合
var img = new Image(); img.setAttribute('lazyload'); img.src = "hoge.png";
実装が部分的で利用シーンも限られるため、当面の間は、imgタグなどに限定すれば、jQuery.lazyLoadで代替すると良いように思えます。Scriptタグについては、defereで代替できる上に、依存関係解決(CommonJS/requireJS)など別の方向性で議論が進んでいるため、あまり役に立たないかもしれません。
3. リソースのキャッシュを操作する
「AppCache」は、Webページのリソースのキャッシュを制御するWeb標準です。標準化の雲行きが怪しくなってはいますが、サーバとクライアント間の通信量そのものを減らすことができるため、パフォーマンス改善に役立ちます。(2014.5.8 : AppCacheの問題点を改善した、「Service Workers」というWeb標準が公開されました。)
AppCacheが無理でも、昔からブラウザは高度なキャッシュ機能を有しており、HTTPヘッダでのキャッシュ制御でもそれなりの改善が行えます。HTTPヘッダだと、以下の項目が挙げられます。
- Expires : コンテンツの有効期限を指定します
- Cache-Control : クライアントのキャッシュ機能を制御します
- ETag : サーバ側でクライアントのキャッシュの新しさを判定します
(※参考 : RFC 2616 - W3C )
4. Webページの非活性を検出する
すごく地味ですが、Webページの非活性を検出して、なんとかしようというアイデアもあります。ブラウザのタブで、非活性な状態の時にはサーバイベント取得のポーリング数を抑えるなど、バックグラウンド処理を減らし、CPUやネットワークなどのハードウェアリソースの消費を抑え、パフォーマンスを改善しようというものです。
「Page Visibility API」は、2013年5月に1版、10月に2版までW3C勧告化が完了し、IEは10から、ChromeもFirefoxも既に実装済みの実用性がかなり高いWeb標準です。このAPIを利用して、非活性を検出しWebアプリの振る舞いを変えることになります。
▼ サンプル
document.addEventListener('visibilitychange', function(){ if ( document.hidden ) { // ポーリング数を減らす処理 } else { // ポーリング数を増やす処理 } }, false);
5. 通信プロトコルを最適化する
★ WebSocket/ServerSentEvents
Webページからの非同期通信の最適化です。ファイアウォール超などの問題を抱えてはいますが、最近はJavaや.NETなどの開発において、アーキテクチャ進化のベースになっているという印象を受けます。Project AvatorにせよSignalRにせよ、リソース同期やRPCを実現するための手段として活用されていることから、今後も目を離せません。
★ SPDY/HTTP2.0
HTTP1系の通信の悪いところを補った新しいプロトコルです。SPDYについてはモダンブラウザで対応が進んでいますが、IEは11からのサポートです。
★ gzip
コンテンツを圧縮することにより、通信コストを減らすという最適化方法です。古い時期から採用されており、IEも6から対応しているのですが、諸々の事情によりIE7以上で利用するほうが良いでしょう。
6. 物理パフォーマンス/時間を検出し最適化する
パフォーマンスの計測を行うためのJavaScriptのAPIは、かなりの数の標準があり、ステータスとしても今の時点で既にW3C標準に進んでいるものも存在します。キーワードベースで並べると、以下の通りです。
- Performance Timeline
- Navigation Timing
- Resource Timing
- User Timing
- Timing control for script-based animations
- Efficient Script Yielding
- Display performance API
- Asynchronous scrolling API
- Diagnostics API
IE10+やChromeでサポートされますが、Firefoxは全体的に微妙な印象です。上記のAPIは、単純に性能測定をするだけに用途は限られず、例えば「Timing control for script-based animations」はゲーム開発におけるフレーム処理に活用されます。(・・・実態としては、環境依存の動作なのでそうもいかないという問題を抱えているのですが、この話はまた今度。)
Navigation TimingやResource Timingは、パフォーマンスの改善ポイントを探すためのWeb標準ですが、ユーザのリアルなWebページ表示速度を取得できる(Real User Monitoringと呼びます)という点では、Webにとって新しい技術と言えます。プラットフォームも増え、機能/動作検出な開発手法が広がると、パフォーマンスの面での検出に活用され幅広い利用方法が模索されそうな気がしています。性能へ配慮したフォールバックみたいなものが、このあたりの標準から生まれるかもしれません。
7. パフォーマンス情報の蓄積
最後に、6で取得した、Webページを表示した際のパフォーマンス情報を、サーバ側へ送信するためのWeb標準です。ユーザの情報を取得する手段としては、Web Beaconというやや泥臭い手法もありますが、JavaScript上で得られる情報が多くなった昨今、より踏み込んだ情報をサーバへ送るための仕組みが求められます。こうした背景から生み出されたのが、「Beacon」というWeb標準です。ただ、中身は今のところ、XMLHttpRequestでもできる簡単なことです。
凄く多いですね。多すぎて、1年後には色んな仕様が全く別物に姿を変えていそうな気がします。ただ、Webプラットフォームのパフォーマンスの悩みは、少し作り込みが複雑なものを作ったことある方なら、必ずしも通っている道のように思えます。
もっと充実化して、改善が進むと良いですね。