パフォーマンスは効率とも言い換えられます。このドキュメントは、パフォーマンスとは何か、ブラウザプラットフォームがその改善にどう役立つか、そのテストと改善にどのようなツールやプロセスが使えるかを、Open Web Apps の文脈で一般的な視点から解説します。
パフォーマンスとは何か?
究極的には、ユーザによって知覚されるパフォーマンスが唯一重要なパフォーマンスです。ユーザは、タッチ、動作、音声を通じてシステムに入力を与え、その引き替えに視覚、触覚、聴覚を通じて出力を感知します。パフォーマンスとは、ユーザの入力に応えるシステム出力の質と言えます。
他の条件がすべて同じであると仮定すれば、ユーザによって知覚されるパフォーマンス (以降 UPP と言います) を除く一部の対象に対して最適化されたコードは、UPP に対して最適化されたコードとの競争に敗れます。ユーザは、例えば、毎秒 100,000,000 件を処理するものの動作がギクシャクとした応答性の低いアプリより、毎秒 1,000 件のデータベーストランザクション処理しか行わなくても応答性の高いスムーズなアプリを好みます。もちろん、これは決して他の指標への最適化が無意味と言うことではありませんが、現実的な UPP 対象が優先されるのです。
次のいくつかの小項目では、最も重要なパフォーマンス指標について取り上げ解説します。
応答性
応答性とは単に、ユーザの入力に対してシステムがどれだけ速く出力 (複数になることもあります) を返すかということです。例えばユーザは、スクリーンをタップしたときに、何らかの方法でピクセルに変化が起きると考えます。このインタラクションでは、応答性の指標はタップからピクセル変化までの所要時間が応答性の指標となります。
応答性は時に、フィードバックで複数の段階を必要とします。アプリケーションの起動は特に重要なケースのひとつであり、これについては後ほど詳しく説明します。
ユーザは無視されたときに不満を募らせ腹を立てるという単純な理由から、応答性は重要です。ある入力に対して応答するまでの間、アプリは刻々とユーザを無視していることになるのです。
フレームレート
フレームレートとは、システムがユーザに表示するピクセルを変更する速度です。これはよく知られている概念です。例えば毎秒 60 フレームを表示するゲームは、理由を説明できなくても毎秒 10 フレームを表示するゲームよりも人々に好まれます。
フレームレートは「サービス品質」の指標として重要です。コンピュータのディスプレイは現実をまねた光を届けることにより、ユーザの「おろかな」目向けに設計されています。例えば、印刷された文字で覆われた紙はいくつかのパターンでユーザの目に光子を反射します。ピクセルを操作することで、リーダーアプリは同様のパターンで光子を発してユーザの目を「だまして」います。
あなたの頭脳が推測するように、動作はギクシャク動いたり不連続であったりするのではなく、むしろスムーズかつ連続的に「更新」します。(ストロボはこれをひっくり返して、不連続な現実の錯覚を作り出すように脳への入力を減らすため、楽しいものです。) コンピュータのディスプレイ上では、単純により高いフレームレートの方が現実をより忠実に再現できます。
注: 人間は通常 60Hz より高いフレームレートの違いを知覚できません。これが、現代のほとんどのディスプレイが 60Hz でリフレッシュするよう設計されている理由です。例えばハチドリには、テレビがおそらくぎくしゃくして非現実的なものに見えるでしょう。
メモリ使用量
メモリ使用量もまた重要な指標です。応答性やフレームレートとは異なり、ユーザはメモリ使用量を直接は知覚できませんが、メモリ使用量は「ユーザ状態」と密接しています。理想的なシステムは、常に 100% のユーザ状態を維持するでしょう: システム内の全アプリケーションが同時に動作し、また全アプリケーションが、ユーザが直前にアプリケーションと行った対話によってもたらされた状態を維持します (アプリケーションの状態はコンピュータのメモリに保存されることが、密接している理由です。)
これは重要かつ直感に反した帰結を見ることとなります。よく設計されたシステムは、空きメモリの量を最大化するようには最適化していないはずです。メモリはリソースであり、また空きメモリは使用していないリソースです。むしろよく設計されたシステムは、ユーザ状態を維持するために可能な限り多くのメモリを使用するように最適化して、同時に他の UPP の目的を達成します。
それはシステムがメモリを無駄使いして良いということではありません。システムが特定のユーザ状態を維持するのに必要なメモリより多くのメモリを使用することは、他のユーザ状態を保持するために使用できたりソースの無駄使いです。実際は、すべてのユーザ状態を維持できるシステムはありません。ユーザ状態のために賢くメモリを割り当てることは、後ほど詳しく説明する通り重要事項です。
電気使用量
最後に挙げる指標は電気使用量です。メモリ使用量と同様に、端末がどれだけ長く他のすべての UPP の目的を維持できるかということから、ユーザは間接的にのみ電気使用量を認識します。UPP の目的を達成するため、システムは必要最小限の電力量だけを消費しなければなりません。
本ドキュメントでは、これらの指標でのパフォーマンスについて説明します。
プラットフォームパフォーマンスの最適化
本章では、Firefox OS と Gecko が全アプリケーションの水準より下で、パフォーマンスに対し通常どのように寄与しているかをおおまかに説明します。開発者あるいはユーザの視点から「プラットフォームは何を行うか」という質問に答えます。
Web 技術
Web プラットフォームには多くのツールがあり、他より特定のジョブに対してより適しているものもあります。アプリケーションのロジックは JavaScript で記述します。グラフィックを表示する場合、開発者は HTML/CSS (高レベルな記述言語) か、<canvas>
要素が提供する低レベルな命令インターフェイス (WebGL を含む) を使用できます。HTML/CSS と Canvas の「中間」には SVG があり、これは両方のメリットを提供します。
HTML/CSS は、時にレンダリング時のピクセルレベルの制御や秒間数フレームを犠牲にしつつ、生産性を飛躍的に高めます。テキストや画像は自動的にリフローされ、UI 要素には自動的にシステムテーマが提供され、また異なる解像度や RTL 言語など、開発者が当初考慮しないかもしれない一部のユースケースについてシステムは「組み込みの」対応を提供します。
canvas
要素は、描画のためのピクセルバッファを開発者に直接与えます。これによって開発者は、レンダリングのピクセルレベルでの制御やフレームレートの正確な制御が可能となりますが、一方で様々な解像度や画面の向き、RTL 言語などに対応する必要があります。開発者は Canvas への描画に、よく知られた 2 次元描画 API か、OpenGL ES 2.0 にほぼ従う「ハードウェアに近い」バインディングである WebGL を使用できます。
注: Firefox OS は、HTML、CSS、JavaScript といった Web 技術によって作られたアプリケーションに最適化されています。わずかな基本システムサービスを除き、Firefox OS で実行されるすべてのコードは Web アプリであり、Gecko エンジン上で動作します。OS のウィンドウマネージャでさえ、HTML/CSS/JavaScript で記述されています。コアオペレーティングシステムがアプリケーションと同じ Web 技術で構築されているため、それら Web 技術のパフォーマンスは重要です。「逃げ道」はありません。これにより、サードパーティアプリも OS 独自の最適化によるあらゆる恩恵を受けられることから、開発者に大きなメリットをもたらします。プリインストールのコードのみ使える「魔法のようなパフォーマンス源」はありません。Firefox OS のパフォーマンスに関する詳細は Firefox OS パフォーマンステスト を参照してください。
Gecko のレンダリング
Gecko の JavaScript エンジンは、ジャストインタイム (JIT) コンパイルに対応しています。これはアプリケーションのロジックを、Java VM など他の仮想マシンに匹敵するほど高速に実行し、また「ネイティブコード」に迫る場合もあります。
HTML、CSS、Canvas を支えている Gecko のグラフィックスパイプラインはいくつかの方法で最適化されています。Gecko 内の HTML/CSS のレイアウトやグラフィックスのコードは、スクロールなど一般的なケースでの無効化や再描画の回数を減らします。開発者はこの支援を「無償で」受けられます。Gecko が「自動的に」、またアプリケーションが canvas
へ「手動で」書き込むピクセルバッファは、ディスプレイフレームバッファへ書き込まれる際にコピー量が最小化されます。これはオーバーヘッドを生み出す中間のサーフェイス (多くのオペレーティングシステムにおける、アプリケーションごとの「バックバッファ」など) を避けたり、コンポジションハードウェアが直接アクセスできるグラフィックスバッファ用の特別なメモリを使用したりすることで実現します。複雑なシーンは最大限のパフォーマンスを得るため、端末の GPU を使用して描画されます。消費電力を低減するため、シンプルなシーンは特別な専用のコンポジションハードウェアで描画し、GPU はアイドル状態または無効化します。
完全に静的なコンテンツは、リッチアプリケーションよりもむしろ例外的です。リッチアプリケーションは animation
や transition
効果とともに動的なコンテンツを使用します。トランジションやアニメーションは、アプリケーションにとって特に重要です。開発者は CSS を使うことで、シンプルで高レベルな構文を使用して複雑な挙動を宣言できます。一方、Gecko のグラフィックスパイプラインは、一般的なアニメーションを効率的に描画するよう、高度に最適化されています。一般的なアニメーションはシステムのコンポジション機能に「押しつけられ」、ハイパフォーマンスかつ低消費電力で描画できます。
アプリケーションの実行パフォーマンスも重要ですが、起動時のパフォーマンスも同様に重要です。Gecko は、多種多様なコンテンツ、つまり Web 全体を効率的に読み込むよう最適化されています。HTML パースの並列処理、リフローや画像デコードの賢いスケジューリング、優れたレイアウトアルゴリズムなど、こうしたコンテンツに対して行われた長年にわたる改良が、Firefox 上で実行される Web アプリケーションのパフォーマンス改善にも適用されます。
注: 起動時のパフォーマンスをさらに改善するには、Firefox OS 固有の詳しい情報を Firefox OS パフォーマンステスト で参照してください。
アプリケーションのパフォーマンス
本章は、「自分のアプリを高速にするために何ができるか」という疑問を持つ開発者に向けたものです。
起動時のパフォーマンス
アプリケーションの起動は一般的に、ユーザが知覚する 3 つのイベントに分けられると言われます。
- 最初に、アプリケーションの「初回描画」です。最初のフレームを描画するのに十分なアプリケーションのリソースが読み込まれた時点です。
- 次に、アプリケーションがインタラクティブになったときです。例えば、ユーザがボタンをタップしてアプリケーションが反応するときです。
- 最後のイベントは「読み込み完了」であり、例えば音楽プレイヤーでユーザのアルバムすべてが表示されたときです。
高速起動の秘訣は、以下 2 点を覚えておくことです。UPP こそが重要であることと、上記のユーザが知覚するイベントそれぞれに至る「クリティカルパス」があることです。クリティカルパスはイベントが発生するまでに実行しなければならない、完全かつ最適なコードです。
例えばいくつかの HTML と HTML にスタイル付けする CSS で視覚的に構成される、アプリケーションの最初のフレームを描画するときは、次のような流れとなります。
- HTML を解析する
- その HTML の DOM を構築する
- DOM の一部である画像などのリソースを読み込みデコードする
- CSS スタイルをその DOM に適用する
- スタイル付けしたドキュメントをリフローする
この中に「一般的ではないメニューに必要な JS ファイルを読み込む」「ハイスコア一覧用の画像を読み込んでデコードする」などはありません。これらの作業項目は、最初のフレームを描画するためのクリティカルパス上にないからです。
これは明らかですが、ユーザが知覚する起動イベントへより早く達するための主な「トリック」は、「クリティカルパス上にあるコードのみ」実行することです。また、シーンをシンプルにしてクリティカルパスを短くしましょう。
Web プラットフォームは高度に動的です。JavaScript は動的型付け言語であり、また Web プラットフォームではコード、HTML、CSS、画像、その他のリソースを動的に読み込むことが可能です。これらの機能は必要ではないコンテンツを起動後に "ゆっくりと" 読み込むことにより、クリティカルパスから外れる作業を遅れて行うために使用できます。
起動を遅らせるもうひとつの問題はアイドル時間であり、(データベースの読み込みといった) リクエストへのレスポンスを待つことにより発生します。この問題を避けるため、アプリケーションは起動時にできるだけ早くリクエストを発行すべきです (これは「フロントローディング」と呼ばれます)。すると後でデータが必要になったとき、それはおそらくすでに読み込まれており、アプリケーションは待つ必要がないでしょう。
注: 起動時のパフォーマンス改善に関する詳しい情報は 起動パフォーマンスの最適化 を参照してください。
また、ローカルにキャッシュされた静的リソースは、高レイテンシかつ低帯域のモバイルネットワークを通じて取得される動的なデータよりも格段に速く読み込まれます。アプリケーション起動初期のクリティカルパスにネットワークリクエストを含むべきではありません。ローカルにリソースをキャッシュすることは、アプリケーションをオフラインで使用可能にする唯一の方法でもあり、標準的な Open Web Apps では、現時点ではこのために HTML5 AppCache を使う必要があります。
注: Firefox OS では、圧縮 ZIP ファイルに「パッケージ」するか、HTML5 AppCache を通じて「ホスト」するか、いずれかの方法でアプリケーションとしてインストールすることで、アプリケーションによるリソースのキャッシュを可能にしています。特定のアプリケーションタイプ向けのこれら選択肢からどのように選択するかは本ドキュメントの範囲を超えますが、一般的にアプリケーションパッケージは最適な読み込みパフォーマンスを提供し、AppCache は比較的遅くなります。インストール可能なアプリは他の OS でもまもなく使えるようになる見込みです。
フレームレート
高フレームレートを得るためにまず考慮すべき重要なことは、適切なツールの選択です。ほぼ静的で、スクロールされ、たまにアニメーションしたりするぐらいのコンテンツには HTML と CSS を使いましょう。レンダリングで精密な制御が必要でありテーマ付けは必要ないゲームなど、高度に動的なコンテンツの実装には Canvas を使いましょう。
Canvas を使用して描画するコンテンツは、目標フレームレートに達するかどうかは開発者次第です。何を描画するかは開発者が直接制御します。
HTML/CSS コンテンツでは、高フレームレートを得るには適切な基本要素を使用します。Firefox は任意のコンテンツのスクロールに高度に最適化されています。これは通常、懸念することではありません。しかし CSS による放射状グラデーションの代わりに静的レンダリングを使用するなど、速さについて一般性と品質を配分することで、スクロールのフレームレートを目標に近づけられることがしばしばあります。CSS メディアクエリ は、それらが必要なデバイスにのみ制限するための折衷策になります。
多くのアプリケーションは「ページ」や「パネル」の移動にトランジションやアニメーションを使用します。例えばユーザが「設定」ボタンをタップすると、アプリケーションの設定画面に遷移したり、設定メニューが「ポップアップ」したりします。Firefox は以下のようなトランジションやアニメーションのシーンに対して高度に最適化されています。
- デバイスの画面サイズとほぼ同じか、より小さいページやパネルを使用する
- CSS
transform
、opacity
プロパティのトランジションやアニメーション
これらのガイドラインに従うトランジションやアニメーションはシステムのコンポジション機能にオフロードされて、最大効率で実行されます。
メモリと電力使用量
メモリや電力の消費の改善は、起動速度向上の問題と似ています。不要な作業を行わない、あまり使われない UI リソースは後から読み込む、効率のよいデータ構造を使用する、画像のようなリソースが十分を最適化する、といったことです。
最近の CPU は、ほぼアイドル状態であるときに低消費電力モードに入ることができます。絶えずタイマーを発生させたり不要なアニメーションを実行し続けたりするアプリケーションは、CPU が低消費電力モードへ移行するのを妨げます。電力効率がよいアプリケーションは、そのようなことを行うべきではありません。
アプリケーションがバックグラウンドに移行するとき、そのドキュメント上で visibilitychange
イベントが発生します。このイベントは開発者の役に立ちます。アプリケーションは、このイベントを監視すべきです。バックグラウンドへ移行するときにできるだけ多くの読み込み済みリソースを手放すアプリケーションは、メモリ使用量が減り、Firefox OS アプリの場合には終了されにくくなります (下記注参照)。この結果、(すでに実行中であるという利点により)「起動」が速くなり UPP も向上します。
注: 先に述べたとおり、Firefox OS は可能な限り多くのアプリケーションを同時に実行し続けようとしますが、通常端末のメモリが不足しているとき、場合によってはアプリケーションを終了しなければなりません。Firefox OS がメモリ使用量をどう管理しているか、メモリ不足が問題になったときに同アプリをどう終了するかといった情報は、Firefox OS でのメモリ不足エラーのデバッグ を参照してください。
アプリケーションパフォーマンス改善のための具体的なコーディングのヒント
以下の実用的なヒントは、上記で解説したアプリケーションパフォーマンスのひとつもしくはそれ以上を改善するのに役立つでしょう。
CSS アニメーションとトランジションを使う
一部のライブラリが提供する animate()
関数は、まだ様々なパフォーマンスの悪い技術 (例えば window.setTimeout()
や top
/left
位置指定) を使っている可能性がありますので、代わりに CSS アニメーション を使いましょう。たいていの場合、実際には CSS トランジション を使えば、やりたいことを実現できます。ブラウザはそうした効果を最適化し、GPU を使用してプロセッサのパフォーマンスへの影響を最小限に抑えつつスムーズに処理するように設計されていますので、問題なく動作するはずです。もうひとつのメリットは、標準的な構文を使って、アプリの他の視覚要素とともにそれらの効果を CSS で定義できるという点です。
CSS アニメーションでは、キーフレーム を使って、非常に細かく効果を調整することが可能です。アニメーションの表示中に実行されたイベントを監視し、そのプロセスの設定点で実行すべき他のタスクを処理することさえ可能です。:hover
、:focus
、:target
といった疑似クラスを使用して、あるいは親要素へ動的にクラスを追加、削除することで、そうしたアニメーションを簡単に実行することができます。
JavaScript でアニメーションを動的に生成あるいは変更したい場合は、James Long が作成した CSS-animations.js というシンプルなライブラリを使うこともできます。
CSS トランスフォームを使う
要素の位置や比率などを調整したいときは、絶対配置を変更し、その数値を自分自身で計算する代わりに、transform
CSS プロパティを使いましょう。その理由は、先ほどと同じくハードウェアアクセラレーションです。ブラウザはそうしたタスクを GPU 上で処理し、他のことを CPU に処理させることが可能です。
さらにトランスフォームは、他の方法ではおそらく実現できない機能を提供します。要素を 2 次元空間内で移動させるだけでなく、3 次元空間内の移動や、ゆがみ、回転といった処理を行えるのです。Paul Irish が、パフォーマンスの観点から translate()
のメリットに関する綿密な分析を行っています。ただ一般的には、CSS アニメーションを使っても同じメリットを得られます。実現したい効果のために適切なツールを使用し、最適化はブラウザに任せましょう。また、要素の位置を変更するには、簡単に拡張可能な方法を使用できます。top
や left
の座標変更でそうした移動をエミュレートするとなると、コードを大量に追加しなければならないでしょう。もうひとつのメリットは canvas
内でも使えるという点です。
注: 今のところ、一部の環境では、ハードウェアアクセラレーションを活用するには translateZ(0)
を使用する必要があります。先に述べた取り、これによってパフォーマンスを改善できますが、メモリ消費量を増大させるといった問題を引き起こす可能性もあります。この点でどう対処すべきかは開発者次第です。多少のテストを行い、あなたの具体的なアプリに最適な方法を見つけてください。
setInterval()
の代わりに requestAnimationFrame()
を使う
window.setInterval()
の呼び出しは、現状では実行可能かどうか定かではない推定フレームレートでコードを実行します。また、ブラウザが実際には描画していない、つまりビデオハードウェアが次の表示サイクルに達していないときにも結果を描画させようとします。これはプロセッサ時間の無駄遣いであり、ユーザの端末のバッテリー寿命を縮める結果にもなります。
代わりに window.requestAnimationFrame()
を使ってみましょう。これは、ブラウザが実際にアニメーションの次のフレームのビルドを開始する準備が整うまで待機し、ハードウェアが実際には何も描画しようとしていない場合は実行されません。この API が持つもうひとつのメリットは、アプリが画面上に表示されていないとき (バックグラウンドのタブにあって他のタスクが実行されている場合など) はアニメーションが実行されないということです。これはバッテリー消費を抑え、ユーザの間で悪評が立つのを防ぐことにもなります。
イベントを即時に実行する
保守的な、アクセシビリティに配慮した Web 開発者として、私たちはキーボード入力にも対応しているクリックイベントを気に入っています。モバイル端末上では、それらは非常に遅くなります。代わりに touchstart
や touchend
を使うべきです。その理由は、アプリの動作が緩慢であると感じさせるような遅延が発生しないということです。タッチ対応を始めにテストする場合、アクセシビリティも犠牲にしてはいけません。例えば、Financial Times はそのために、一般公開もされている fastclick というライブラリを使用しています。
インタフェースをシンプルに保つ
HTML5 アプリに見られる大きなパフォーマンス問題のひとつに、多くの DOM 要素を移動させることで、特にグラデーションやドロップシャドウを多用している場合、あらゆる動作が緩慢になるということが挙げられます。デザインをシンプルにし、ドラッグ&ドロップ処理を行う場合は仮の要素を移動させることで、そうした問題を大幅に改善することが可能です。
例えば、アプリ内に要素の長大なリスト (ツイート一覧など) がある場合、それらをすべて移動させようとしてはいけません。その代わりに、表示されているツイートと、その前後にある多少のツイートだけを DOM ツリー内に保持することも可能でしょう。残りは隠すか削除しましょう。DOM へアクセスする代わりに JavaScript オブジェクト内にデータを保持することで、アプリのパフォーマンスを大幅に向上させることができます。表示を、データそのものではなく、データの表現として考えましょう。これは本来の HTML をソースとして使えないということではありません。ユーザがツイートを読んで 10 要素分スクロールしたら、表示されていない 100 要素を移動する代わりに、結果リスト内の位置によって最初と最後のコンテンツを変更するのです。同じテクニックはスプライト処理を行うゲームにも当てはまります。要素が画面上にない場合は、それらにポーリングを行う必要はありません。代わりに、画面外に出た要素を画面内に入る要素として再利用すれば良いのです。
一般的なアプリケーションパフォーマンス解析
Firefox、Chrome、その他のブラウザには、遅いページレンダリングの原因を突き止めるのに役立つ組み込みのツールが含まれています。特に、Firefox のネットワークモニタ は、ページ上のネットワークリクエストがいつ発生したか、どのぐらいの大きさで、どのぐらい時間が掛かったかという正確なタイムラインを表示できます。
実行に時間の掛かる JavaScript コードがページに含まれている場合、JavaScript プロファイラ で最も遅いコードの行数を特定できます。
組み込み Gecko プロファイラ は、プロファイラの実行中にブラウザコードのどの部分が遅いかについてさらに詳しい情報を提供する大変便利なツールです。これは使い方が多少複雑ですが、多くの有益な詳細情報を提供してくれます。
注: これらのツールは Android ブラウザでも使用できます。Firefox を起動し リモートデバッグ を有効にしてください。
YSlow (Firebug アドオンの拡張機能) は、パフォーマンス改善のため非常に有益なアドバイスを提供してくれます。特定された問題と提案された解決策の多くはモバイルブラウザで特に有益なものです。絶対に YSlow を実行し、そのアドバイスに従うべきです。
特に、ネットワークリクエストを多数実行すること、モバイルブラウザでは時間が掛かります。巨大な画像のレンダリングや CSS グラデーションも時間が掛かるでしょう。モバイルハードウェアは時として利用可能な帯域をすべて活用するには遅すぎるため、巨大なファイルのダウンロードは高速なネットワーク上でさえ時間が掛かります。モバイル Web パフォーマンスに関する有益で一般的なヒントは、Maximiliano Firtman の モバイル Web ハイパフォーマンス プレゼンテーションにあります。
テストケースの作成とバグの報告
Firefox と Chrome の開発者ツールが問題発見の役に立たない場合、あるいは Web ブラウザが問題を引き起こしている可能性があるという情報を示している場合、問題を最大限に分離した最小限のテストケースを用意してみてください。おそらく問題の診断に役立つでしょう。
HTML ページの (埋め込まれている画像、スタイルシート、スクリプトを含む) 静的なコピーを保存して読み込むことで問題を再現できるか確かめてください。その場合、その静的なファイルを編集してあらゆる個人情報を削除した上で、他の人に送って助けを求めましょう (例えば Bugzilla にバグを報告するか、サーバ上に置いて URL を共有してください)。上記のツールを使って収集したプロファイル情報があればそれも共有すべきでしょう。