Ajax パフォーマンスの分析

最新のツールを採り入れて仕事を片付ける

Ajax (Asynchronous JavaScript + XML) が対話性とパフォーマンスに対するユーザーの期待を膨らませ続けているなか、開発者たちはますます Ajax を Web アプリケーションの必須コンポーネントとして扱うようになっています。多くのコードがクライアント・サイドに移されてネットワーク・モデルが変わるにつれ、コミュニティーは Ajax ならではのパフォーマンス問題に対処するためのツールをさらに作成することで対応しています。この記事では、Ajax で強化されたアプリケーションに潜むパフォーマンス問題を見つけ出し、修正するツール・セットについて検討します。

Kristopher William Zyp (kriszyp@xucia.com), Software Developer, Xucia

Kristopher ZypKris Zyp はソフトウェア開発者、コンサルタント、そして Xucia の創立者であり、JavaScript の永続性とコルーチン、そしてその他の言語機能の分野を専門としています。彼は Persevere (JavaScript 永続オブジェクトのマッピング・フレームワーク)、Strands (JavaScript のコルーチンおよびスレッド化サポート)、Authenteo (Ajax ベースの Web コンテンツ管理システム)、JSPON 仕様を開発した他、JSPON ソースを使用するためのオープン・ソースのツールも開発しました。



2008年 4月 24日

Ajax を使ってアプリケーションを強化する大きな動機の 1 つは、パフォーマンスです。Ajax はページ全体のリクエストを送信せずにサーバーと通信するという方法で応答時間を短縮します。このように応答時間を短縮することによって、Ajax は顕著に改善されたユーザー・エクスペリエンスをもたらすことができます。ただし、Ajax アプリケーションのパフォーマンスを分析して改善するには、従来の Web アプリケーションとは異なったツール・セットが必要です。そこで、この記事では Ajax アプリケーション用のツール・セットを検討し、これらのツール・セットを使ってパフォーマンス問題を発見し、修正する方法を紹介します。

よく使われる頭字語

  • CSS: Cascading Style Sheets
  • HTML: Hypertext Markup Language
  • XML: Extensible Markup Language
  • HTTP: Hypertext Transfer Protocol

Ajax アプリケーションのパフォーマンスは、Web アプリケーションの以下をはじめとする側面が基準となります。

  • サーバーの応答時間
  • ネットワーク転送時間
  • クライアントの JavaScript 処理時間

従来の Web アプリケーション開発では、サーバーの応答時間がパフォーマンス分析における第一の焦点となります。そのため、大抵のパフォーマンス分析ではアプリケーション・サーバーがいかに短時間でリクエストを処理し、必要なアプリケーション・ロジックを実行してレスポンスを生成できるかを測定します。Ajax アプリケーション開発でも、このようなパフォーマンスはアプリケーションのパフォーマンスの重要な側面となりますが、この点については一般によく理解されているため、この記事ではパフォーマンスの他の部分に焦点を当てます。

ツール

Web アプリケーションで改善しなければならない側面を理解するには、そのアプリケーションのコンポーネントを正しく分析する必要があります。この記事では、Firefox の Firebug 拡張機能、そして YSlow アドオンを使用して Web アプリケーションを計測する方法を取り上げます。これらのツールをインストールしたら、開発中のサイトに接続し、Firefox のステータス・バーで YSlow をクリックしてください。すると Firebug 内に YSlow インターフェースが開くので、Performance ボタンをクリックします。この操作によって YSlow がアプリケーションを分析し、アプリケーションのネットワーク転送時間の内訳をレポートします (図 1 を参照)。

図 1. YSlow レポート
YSlow レポート

ネットワーク転送時間

ほとんどの Web アプリケーションでは、ネットワーク転送時間が最大のボトルネックです。YSlow レポートにより、ネットワーク転送のさまざまな側面を分析し、転送時間を短くするために必要な措置を把握することができます。

HTTP リクエスト数の削減

すべての HTTP リクエストは、そのリクエストがサーバーに送信されてレスポンスを取得するまでにある程度の時間がかかります。レスポンスが小さなものだとしても、基本となる往復時間が伴います。この時間は、レイテンシーと呼ばれます。YSlow では、HTTP リクエストの数を基準に等級を付けます。リクエストの数が多ければロード時間が明らかに長くなりますが、この場合、ページを単純化してロードしなければならないコンポーネント数を少なくすれば HTTP リクエストの数を減らすことができます。画像に関するリクエストの数を減らすには、CSS Sprites (スプライト) を使用するという方法があります。CSS スプライトを生成するツールは入手可能です (「参考文献」セクションを参照)。スクリプトおよび CSS のリクエストの数を減らすには、ページにインラインで組み込むか、複数のスクリプトまたは CSS ファイルを 1 つにまとめてください。

HTTP リクエストの数は、HTTP キャッシュの有効期限ヘッダーに、ブラウザーがコンポーネントをキャッシュに入れておくことのできる期限の日付を指定するという方法で減らすことができます。ユーザーがページ間をナビゲートしたり、サイトに再アクセスしたりするときに、該当するコンポーネントをキャッシュに入れられるようにすることが重要です。そうすれば、サイトにアクセスするたびにコンポーネントをダウンロードする必要がなくなります。適切な有効期限ヘッダーが指定されていれば、プロキシーも頻繁にロードされるコンテンツをキャッシュに入れることができます。以下に示すのは、有効期限ヘッダーの一例です。

Expires: Wed, 10 Mar 2009 10:00:00 GMT

有効期限をあまりにも先の日付にすると、コンテンツを変更したとしてもブラウザーがコンテンツをキャッシュに入れたままになってしまうので、有効期限までの日数を減らしてください。また、ファイルの新しいバージョンを作成するときにファイル名を変更することで、新規バージョンがリリースされるときに新しい URL が要求されて、ブラウザーが新しいリクエストを作成することもできます。有効期限ヘッダーを追加するように Apache を構成するには、以下のように ExpiresDefault ディレクティブを使用します。

ExpiresDefault "access plus 10 years"

YSlow では、Stats ボタンをクリックしてページのダウンロード・サイズの合計を確認することもできます。YSlow は、ビジターが初めてアクセスする場合 (何もキャッシュされてない状態) のページ・サイズ、そしてその後にアクセスした場合 (キャッシングを使用できる場合) のページ・サイズを示します。

代わりの DNS ルックアップ

HTTP リクエストに関わってくるのは、サーバーとの往復だけに限りません。リソースが複数のホスト名またはドメイン名を使用している場合、ブラウザーは DNS (Domain Name System) ルックアップも行わなければならなくなります。YSlow は複数の名前のルックアップが必要な場合にはアラートを出しますが、複数の DNS 名はパフォーマンス上のメリットにもなり得るということに注意することが重要です。大抵のブラウザーがホスト名ごとに許容する接続数は 2 つだけですが、ホスト名が複数あれば、それ以上の接続数 (したがって、より大量の並行ダウンロード) が許容されるからです。

ウィキペディアによると、minify (サイズを縮小) するということは、ソース・コードの機能性を変えることなく不要なすべての文字を取り除くというプロセスです。通常、不要な文字には空白文字、改行文字、コメント、また場合によってはブロック区切り文字などが含まれます。これらの文字はコードを読みやすくするために追加されているものですが、コードの実行には必要ありません。

コンポーネント転送サイズの縮小

HTTP リクエスト数の削減に加え、要求対象のコンポーネントのサイズを小さくすることも有効です。それには、特定のフォーマットを圧縮する技術を適用することができます。YSlow はどの技術を適用するとレスポンスのサイズを縮小できるかを示します。

JavaScript コード、CSS、HTML のサイズを縮小するには、不要な空白とコメントを削除するという方法があります。JavaScript コードの場合は、変数の名前を変更することでサイズをさらに小さくすることができます。JavaScript の圧縮に有効なツールは Packer および YUI Compressor です。YUI Compressor は、CSS の圧縮もサポートします。サイズを縮小するためのツールについては、JavaScript CompressorRater で比較することができます (「参考文献」セクションを参照)。

リソースの圧縮に最も効果的な方法の 1 つは、テキスト・ベースのリソースに対して gzip (GNU zipの略) を有効にすることです。gzip を使用すると、通常はコンテンツのサイズを約 70% 縮小することができます。ただし、すでに圧縮済みのリソース (画像や動画など) には gzip を使用しないでください。gzip の有力候補としては、CSS、HTML、JavaScript コード、XML、JSON (JavaScript Serialized Object Notation) などが挙げられます。Apache 1.3 は mod_gzip で gzip をサポートし、Apache 2.0 は mod_deflate を使用します。

リソースのサイズという点では、HTTP レスポンスのサイズを最小化するだけでなく、HTTP 要求のサイズを最小化することも重要になります。多くのインターネット・ユーザーにとって、アップロード速度はダウンロード速度よりも大幅に遅いため、リクエストのサイズのほうがパフォーマンスに及ぼす影響は甚大です。大量の URL、大規模な投稿データ、そして過剰なヘッダーもリクエストのサイズを大きくします。Firebug でリクエストの内容を見るには Net タブを表示してください (図 2 を参照)。それぞれのリクエストを展開すると、リクエストのヘッダーを確認することができます。ヘッダー・サイズを不必要に大きくする最も一般的な原因は、大量の cookie です。cookie はリクエストごとにヘッダーに組み込まれます。したがって、大量の cookie はかなり余分なオーバーヘッドを追加します。

図 2. Firebug の Net パネル
Firebug の Net パネル

J2EE (Java™ 2 Platform, Enterprise Edition) アプリケーションは、Resource Accelerate という単純なフィルターによって以上に挙げたパフォーマンス改善のいくつか (キャッシングの有効期限、gzip、JavaScript 圧縮) を適用することができます。さらに、pack:tag JSP (JavaServer Pages) タグ・ライブラリーを使用してリソースを圧縮することもできます。それぞれの技術によって他のオプションもあるので、詳しくは「参考文献」セクションを参照してください。

ネットワーク転送のその他のパフォーマンス改善

YSlow のもう 1 つの推奨案は、コンテンツ・デリバリー・ネットワーク (CDN) を使用することです。CDN はサーバーの分散ネットワークを提供し、エンド・ユーザーにより近い場所からコンテンツを配信することで応答時間を短縮します。

また、CSS とスクリプトを適切に順序付けて Web ページのレンダリング速度を向上させるという手段もあります。YSlow は、CSS およびスクリプト宣言の場所を分析し、その順序の改善方法に関する情報を提供します。推奨される順序は、CSS をすぐにレンダリングに使用できるように CSS 宣言はページの先頭に配置し、対話用の JavaScript コードをロードする前にページをレンダリングできるようにスクリプトはページの最後に配置することです。

JavaScript の処理時間

Web ページがサーバーによって正常に生成されてブラウザーに転送された後は、Ajax アプリケーションは通常、JavaScript コードを使ってユーザーとの対話動作を行います。ほとんどのユーザーはページが完全にダウンロードされるまで暫く待つ心構えができていますが、優れた対話動作はフィードバックが迅速であるかどうかにかかっています。そのため、ページ上のさまざまなコンポーネントに素早く応答することが、快適なユーザー・エクスペリエンスに最も重要となる点です。また、ブラウザーはリソースがダウンロードされている間も引き続き反応するのが通常ですが、JavaScript コードが絶え間なく実行されていると、ブラウザーが完全に動かなくなってしまうこともあります。

Firebug にはプロファイル作成ツールが付属しています。このプロファイラーを使うには、コンソール (Console) タブを表示してプロファイル (Profile) をクリックし、プロファイラーを起動してください。プロファイルは、Web アプリケーションのどの部分が JavaScript コードを大量に使っているかを理解する手助けとなります。さらに、テスト対象のアクティビティーを何回か繰り返すことで、プロファイラーはより正確な結果をもたらします。例えば、ページをロードするときに実行される JavaScript コードが大量にある場合には、ページ・ロードを複数回実行してください。また、JavaScript によるホバー・イベントのハンドラーがある場合には、暫くマウスをページのあちこちに動かしてプロファイラーが妥当な量の情報を収集できるようにしなければなりません。作業アクティビティーを終えたら、Profile ボタンをもう一度クリックします。すると、プロファイル結果が表示されます (図 3 を参照)。

図 3. Firebug のプロファイル結果
Firebug のプロファイル結果

プロファイル結果にはプロファイル中に行われたすべての関数呼び出しが一覧にされ、エントリーごとに関数が呼び出された回数、それぞれの関数呼び出しにかかった処理時間に関する統計情報が示されます。Time 列にはその関数を呼び出してから戻るまで待機した時間の合計が記載され、Own Time 列にはその関数を呼び出してから戻るまでにかかった時間から、その関数内部で別の関数を呼び出して実行していた時間を差し引いた時間が記載されます。通常は、この Own Time が最も重要な時間情報となります。この時間はコストのかかる処理の大半が発生した部分を表し、この時間に基づいて Percent 列の値が算出されるためです。デフォルトでは、Firebug は Percent 列を基準 (最大の値を先頭に配置) にソートを行います。このソート順は最もコストのかかる呼び出しが先頭に来るため、プロファイルが読みやすくなる便利な方法であり、関数のパフォーマンスの改善に専念することができます。Firebug で関数のソースにアクセスするのは簡単です。リスト内のエントリーをクリックするだけで、その関数が表示されます。

JavaScript 関数のパフォーマンスを評価する際には、関数が呼び出された回数に注意することも肝心です。呼び出し回数が多い場合、その関数自体に必ずしも時間がかかっているわけではなく (関数の平均処理時間を見ればわかります)、頻繁に呼び出されているだけに過ぎない可能性があります。関数が期待される以上に何度も使用されていることが、パフォーマンスを劣化させる原因にもなります。その一例として、onmousemove のようなホバー・イベントのハンドラーが多数のイベントを発生させることは珍しくありません。

特定の関数に処理時間がかかりすぎていることが明らかな場合には、JavaScript コードで考えられる問題を調べる必要があります。表 1 に、時間がかかることがわかっている JavaScript の演算をリストします。ベンチマークに関する詳細は、「参考文献」セクションを参照してください。

表 1. 時間のかかる JavaScript 演算
演算内容
DOM アクセス一般に、DOM の操作は通常の JavaScript コードの場合よりも時間がかかります。DOM の操作は一般に避けられないものですが、なるべく最小限にしてください。一例として、DOM メソッドを用いて HTML を作成するよりも、ストリングを使って動的に HTML を作成して innerHTML を設定するほうが時間は短くなります。
evaleval メソッドを使用するとスクリプトの評価に多大なオーバーヘッドがもたらされるので、できる限りこのメソッドは使用しないようにしてください。
withwith 文を使用すると追加のスコープ・オブジェクトが作成され、これらのオブジェクトによって変数へのアクセスが遅くなるとともに曖昧性がもたらされます。
for-in ループ配列の走査には for-in ループではなく従来の for (var i=0; i<array.length;i++) を使用します。残念ながら、ほとんどの JavaScript 環境での for-in ループ実装には時間がかかります。

その他のブラウザー

Firebug と YSlow を備えた Firefox は、明らかにプロファイル作成に最適です。一方、Mac OS X の Safari では、Web Inspector を使用して HTTP 要求を分析することもできます。JavaScript パフォーマンスのプロファイル作成には、手動で特定の関数のパフォーマンスを測定するという手法があります。関数を手動で測定するには、Date 関数を使って実行時間を測定します (リスト 1 を参照)。

リスト 1. 手動による時間測定
function myFunctionToTest() {
	var start = new Date().getTime();
	... // body of the function
	var totalTime = new Date().getTime() - start;
}

developerWorks の Ajax リソース・センター
Ajax resource center にアクセスしてください。ここは、無料のツール、コード、そして Ajax アプリケーションの開発に関する情報が用意されたワンストップ・ショップです。また、Ajax のエキスパートである Jack Herrington がホストする活発な Ajax コミュニティー・フォーラムは、あなたが今まさに探している答えを持っているかもしれない開発者仲間と交流する手段となります。

特にパフォーマンスの障害となる可能性のある問題は、Windows® Internet Explorer® がメモリー管理を得意としていないことです。パッチを当てていない Internet Explorer 6 以前のバージョンでは、作成されるオブジェクトとプロパティーの数が増えるにつれ振る舞いは徐々に遅くなっていきます。一般に、古いバージョンの Internet Explorer ではオブジェクトの数が 5000 を超えると極端に動作が遅くなるはずです。

まとめ

Firebug と YSlow を使用すれば、Web アプリケーションを徹底的に分析し、根拠に基づいた変更によってパフォーマンスを改善することができます。YSlow が提供するのは、ネットワーク転送時間の短縮に役立つ詳細情報です。一方、Firebug が行う JavaScript のプロファイリングの詳細な分析によって、改善が必要不可欠なコードの領域を判断できるようになります。この 2 つのツールが一体となって、最高レベルのユーザー・エクスペリエンスをもたらすパフォーマンスを備えた Web アプリケーションの構築を手助けします。

参考文献

学ぶために

製品や技術を入手するために

  • Firebug をダウンロードして、その詳細を学んでください。
  • Firebug をダウンロードしたら、次に YSlow を調べてください。
  • Firebug 1.1 ベータ版を試してみてください。
  • Resource Accelerate を使って Web サイトおよびアプリケーションのパフォーマンスを改善してください。
  • pack:tag をダウンロードしてください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=311955
ArticleTitle=Ajax パフォーマンスの分析
publish-date=04242008