Ajax に関する 5 つのベスト・プラクティス

より適切な Ajax 開発のためのヒントとツール

日常的な Ajax (Asynchronous JavaScript + XML) 開発に適用できる 5 つのベスト・プラクティスを学びましょう。この記事では、Ajax を使用する RIA (Rich Internet Application) の開発に使用されるデータ・フォーマットとエラー処理、そしてツールを紹介します。より効率的で堅牢な Ajax コードを作成する上で、これらのプラクティスがいかに役立つかを学びましょう。

Nathan A. Good, Senior Consultant and Freelance Developer, Freelance Developer

Nathan GoodNathan A. Good はミネソタ州の Twin Cities エリアに住んでいます。彼はプロとしてソフトウェア開発やソフトウェア・アーキテクチャー、システム管理などを行っています。彼はソフトウェアを書いている時以外は、PC やサーバーを構築したり、新しい技術について資料を読んだり、そうした技術に取り組んだり、彼の友人達をオープソース・ソフトウェアに移行させようとしたりしています。彼は数多くの本や記事を執筆、あるいは共同で執筆しており、その中には『Professional Red Hat Enterprise Linux 3』や『Regular Expression Recipes: A Problem-Solution Approach』、『Foundations of PEAR: Rapid PHP Development』などがあります。



2010年 11月 09日

この記事では、Web アプリケーションで Ajax 開発を行う際に活用できる 5 つのプラクティスを紹介します。

これらのプラクティスは、Ajax コードを高速に実行する、堅牢な JavaScript コードを作成する上で役立ちます。これはユーザーにとっても良いことです。

Ajax の概要

Ajax は比較的新しい用語として、かなり前から存在していた技術 (HTTP によって非同期呼び出しを行うための JavaScript コードと XML、そしてオブジェクト) を表すために使われています。Ajax がよく使われる場合としては、HTML ページ全体を送信してリロードするという動作を避けたい場合、特に、ページ全体のリロードを必要としないアクションをユーザーが実行する場合です。

ここ数年、Ajax 対応のサイトを作成するためのツールが改善されるにつれ、Ajax は従来以上に幅広く使われるようになっています。この記事で紹介するプラクティスを活用し、Ajax と JavaScript コードを使用する、より優れた Web アプリケーションを作成してください。


呼び出しを最小限にとどめる

当然と思えるかもしれませんが、Ajax を使用する Web アプリケーションのパフォーマンスを高める方法の 1 つは、呼び出しの回数を最小限にすることです。

呼び出しの回数を最小限にするための 1 つの方法は、複数の呼び出しを集約することで呼び出しの回数を減らす方法です。データが比較的小さい場合 (「データを小さくする」を参照)、大半のネットワークでの大敵は遅延です。遅延というのはブラウザーがサーバーやサービスへの接続を完了するのに要する時間であり、場合によると接続時間の大きな部分を占めることがあります。ユーザーが経験する待ち時間の合計は、ブラウザーのキャッシュの設定、DNS クライアント、物理的な接続など、いくつかの要因に依存します。

Web アプリケーションでの呼び出しの回数を最小限にする方法は、簡単な公式や 1 つのコード・スニペットを読むだけで理解できるわけではありません。ただし、簡単な演習をしてみると、クライアントからサーバーへの Ajax 呼び出しの回数を減らすための効果的な方法を実証することができます。例えばサンプルとして、中古のバイクを購入するための Web アプリケーションを考えてみてください (図 1)。

図 1. 中古のバイクを検索するための単純な Web ページ
このスクリーン・ショットには、メーカー、モデル、年式に関するドロップダウン・ボタンと、郵便番号のフィールドが表示されています。

まず、ユーザーはバイクの年式 (year) を選択します。続いてメーカー (make) を選択し、最後にモデル (model) を選択します。この選択操作の間、Ajax はバックグラウンドで実行されているため、ユーザーが選択を行うとドロップダウン・ボックスは更新され、フィルタリングされたリストが表示されるようになります。これにより、ユーザーは容易に選択を行えるようになります。

演習では始めに、クライアントを表す 1 つのボックスとサーバーを表す 1 つのボックスを含む簡単な図を作成します。そして図 2 に示すように、サーバーからユーザーのデータを取得するためにブラウザーが行う Ajax 呼び出しを表す線を引きます。

図 2. Ajax 呼び出しを図で表現する
ブラウザーとサーバーのボックスからそれぞれ下に破線が伸びており、その 2 本の破線の間がそれぞれメーカー、モデル、在庫を取得するための 3 本の実線で結ばれています。

メーカー (make) とモデル (model) を取得するための呼び出しを 1 つの呼び出しにまとめることで、設計を改善することができます。1 回の呼び出しでメーカー (make) を取得し、別の 1 回の呼び出しで (model) を取得する代わりに、モデル (model) をキャッシュするようにします。つまり新しいコードでは、ユーザーがメーカー (make) を選択した場合には、入手可能なモデルの一覧を単純にキャッシュから取得します。ローカルにキャッシュされたリソースからデータを取得した方が、同じデータをサービスから取得するよりも、はるかに高速です。何度もサービスを呼び出すのを避けることで、サービスの呼び出しに伴う遅延が発生しないようにすることができます。この新しい通信方式は図 3 のようになります。

図 3. メーカー (make) を取得するための呼び出しとモデル (model) を取得するための呼び出しを 1 つにまとめた場合の Ajax 呼び出し
ブラウザーとサーバーのボックスからそれぞれ下に破線が伸びており、その 2 本の破線の間がそれぞれメーカーおよびモデルを取得するための実線と、在庫を取得するための実線の 2 本で結ばれています。

ここまでの段階で、設計をしなおすことによってブラウザーとサーバーとの通信から呼び出しを 1 つ減らすことができました。リスト 1 のコードを使うと、さらに呼び出しの回数を減らすことができます。リスト 1 では、取得したデータを数行の重要なコードによって配列に格納し、後で参照できるようにしています。

リスト 1. データをローカルにキャッシュする
var choices = new Array();

function fillChoiceBoxes(year) {

    // see resources for links to dojo toolkit...
if (dojo.indexOf(choices, year) == -1) {
        // go get the         
    } else {
        // make the ajax call and fill the choices.    
choices[year] = result; // result of ajax call.
    }

    // calling a function to fill the values...
    fillSelect(dojo.byId('makes'), choices[year]);

}

ユーザーが 2 つの異なるモデルを検討していて、2 つのモデルの間を行ったり来たりしている場合には、この Web アプリケーションは何度もサービスを呼び出す代わりに、ローカルにキャッシュされたデータを使用します。キャッシュするデータは (少なくとも、そのユーザー・セッションが継続されている間は)、静的なデータのみにします。キャッシュする必要のないデータをキャッシュすることによって大量の問題を抱え込むようなことがあってはなりません。

この例で示したように、クライアントからサーバーへの往復の回数を減らし、可能な場合にはデータをキャッシュすることで、呼び出し回数を最小限にとどめることができます。


データを小さくする

データ処理のパフォーマンスを高めるためには、サーバーからクライアントに送信されるデータを可能な限り小さくします。それを効果的に行うためには、サービスからクライアントに送信されるメッセージのフォーマット設定を指示できる程度にサービス・レイヤーを制御できる必要があります。

クライアントとサーバーの間でのメッセージ・フォーマットとしては XML が一般的ですが、そこには多くの理由があります。そうした理由の 1 つは、XML にシリアライズしてくれるライブラリーやフレームワークが沢山あることです。

ただし、JSON (JavaScript Serialized Object Notation) と比べた場合、XML はメッセージ用としては冗長なフォーマットで、JSON の方がメッセージ・フォーマットとして簡潔です。現在、サービスからクライアントへオブジェクトを送信するためのメッセージを JSON 形式で容易に作成できるようにするライブラリーは数多くあります。

多くのクライアント・サイド・ライブラリー (Dojo Toolkit など) では、サービスが使用する送信フォーマットを指定することができます。サービスのレスポンスに JSON を使用する場合には、パラメーターを指定することで、同一のクライアント・オブジェクトを使用することができます。

リスト 2 のコードについて考えてみましょう。このコードは motorcycle オブジェクトを XML を使って表現する方法を示しています。

リスト 2. XML を使用した motorcycle データ
<motorcycle>
  <year>2010</year>
  <make>Motocool</make>
  <model>Uberfast</model>
</motorcycle>

今度はリスト 3 について考えてみましょう。このコードは同じデータを JSON を使って表現しています。リスト 3 の方が (ホワイト・スペースを削除すれば) リスト 2 よりも約 25% 小さなサイズになっています。

リスト 3. JSON を使用した motorcycle データ
{ 
"motorcycle" : { 
    "year" : "2010", 
    "make" : "Motocool", 
    "model" : "Uberfast"
    }
}

データのサイズが小さいため、サービスからクライアント (またはクライアントからサービス) への送信時間が短くなるだけではなく、文字列が短いため、構文解析の時間も短くなります。

データを設計する際には、送信されるデータに含まれる文字が可能な限り少なくなるようにする必要があります。


コンポーネントをプリロードする

Ajax 呼び出しに使用する JavaScript ファイルや画像などのコンポーネントをロードすることで、ブラウザーのキャッシュを活用することができます。重要な注意点として、JavaScript ファイルや画像をプリロードすることによるメリットを活かせるのは、キャッシュを有効にしているユーザーのみになりますが、大部分のユーザーはキャッシュを有効にしています。

外部の JavaScript ファイルをプリロードするためには、その JavaScript ファイルを含める場所を、ワークフローの始めの方にあるページにします。ただし、そうした方がよい場合というのは、その始めの方にあるページの方が最適化対象のページよりもサイズが小さく、リソースも少ない場合のみです。例えば、ユーザーにワークフローを紹介する比較的軽いページがある場合には、プリロードが有効です。「呼び出しを最小限にとどめる」セクションで説明した、バイクを購入する例を考えてみてください。この例では、フローの始めの方のページでドロップダウン・ボックスを含むページの Ajax コードをすべて含む重たい JavaScript コードをプリロードすることができます。

Ajax 呼び出しを行った結果として画像が更新される場合には、画像をプリロードしておくと非常に有効です。画像がプリロードされていれば、ユーザーは、要素の上でマウスを動かしたり、ドロップダウン・ボックスから選択したり、ボタンをクリックしたりしたときに、ブラウザーが画像を取得するのを待つ必要がありません。Ajax は非同期で実行されますが、画像をサーバーからクライアントに送信するためには少し時間がかかるため、完全にダウンロードされるまでは、ユーザーのブラウザーに画像は表示されません。

リスト 4 に示す例では、リストからバイクのメーカー (make) を選択する際に使われる画像は、標準的な JavaScript コードを使ってプリロードされています。

リスト 4. 標準的な JavaScript コードを使って画像をプリロードする
<html>
<head><title>Preload example</title></head>
<body>
<!-- web page... -->
<script type="text/javascript" language="javascript">
    var img = new Image();
    img.src = "http://path/to/motocool.jpg";
</script>
</body>
</html>

画像をページにプリロードする際、JavaScript の配置は重要です。HTML の中に JavaScript コードを配置する場合、Web ページのロードが遅くなる恐れのある場所に配置することで Web ページのロードに影響を与えることは避けなければなりません。一般的なルールとして、<script> 要素に囲まれた JavaScript コードは HTML ページの最後に配置するようにします。ブラウザーが 1 度にダウンロードできるリソースの数はある程度限られているからです。可能であるなら HTML ページの最後の方にスクリプトを配置することで、ブラウザーによる画像やその他のリソースのロードが速くなります。

HTML 5 では、<script> タグに対し、新しい async 属性を使用することができます。async 属性により、JavaScript コードを非同期で実行するようにブラウザーに指示することができます。その結果ブラウザーは、Web ページ上で他の何かが実行されている間に JavaScript コードを実行することができます。


エラーをスマートに処理する

JavaScript コードの中で定義される関数はすべて、悪意のある入力がされることを想定する必要があります。なぜなら、防御的に作成されたコードの方が try... catch 文を使ってエラー処理を行うよりもパフォーマンスに優れているからです。例えば、ユーザーの入力に基づいて JavaScript 関数を使って計算する必要がある場合であれば、まず入力をチェックしてから計算を行います (リスト 5)。

リスト 5. ユーザーによる入力をチェックする
function caculateDistance(source,dest) {
    if (! isNaN(source) || ! isNan(dest)) {
        dojo.byId("errors").innerHTML = "Please provide a valid number.";
    }
}

たとえ防御的なコードを作成した場合であっても、可能であれば try... catch 文とエラーのコールバックを使用するのが適切な方法です。リスト 6 は JavaScript コードの中で try... catch 文を使ってエラーをキャッチする方法を示しています。

リスト 6. try... catch 文を使ってエラーを処理する
function calculateDistance(source,dest) {
    try {
        // do some calculations...
    } catch (error) {
        dojo.byId("errors").innerHTML = "An error occurred while adding the numbers";
    }
}

リスト 7 は Dojo Toolkit の xhrGet() メソッドを呼び出す一方でエラーのコールバックを使用する方法を示しています。error 引数はオプションなので、エラー・ハンドラーの指定を省略しそうになりがちです。

リスト 7. xhrGet() を呼び出すとともにエラーのコールバックを使用する
var args = {
    url: "/moin_static185/js/dojo/trunk/dojo/../dojo/NoSuchFile",
    handleAs: "text",
    preventCache: true,
    load: function(data) {
        // do something when successful...
    },
    error: function(error) {
        dojo.byId("errors").innerHTML = "An error occurred while getting the data..";
    }
}
var ajx = dojo.xhrGet(args);

Web ページ上でエラーをどう処理するかは、技術の問題であると同時にビジネスの問題でもあります。何か問題があった場合に、ユーザーに対してどんなメッセージを表示したいのかを必ず顧客に尋ねる必要があります。どのようなメッセージであれ、ユーザーに表示するメッセージはビジネスに影響を与えるからです。顧客は、例外が発生した場合に有効なデフォルト動作について助言してくれるかもしれません。

最後になりますが、エラーの内容を JavaScript のアラートで表示してはなりません (リスト 8)。ユーザーはソフトウェア・エンジニアではありません。そのため、どのような内容をアラート・ボックスに表示しても、おそらくユーザーにとっては何も意味をなしません。ユーザーにとって対処不能なメッセージを表示するという不便に加え、ユーザーはアラート・ボックスを閉じて Web ページに戻るという余分な操作をしなければなりません。

リスト 8. エラー処理として JavaScript のアラート・ボックスを使うことは避ける
function calculateDistance(source,dest) {
	try {
		// do some calculations...
	} catch (error) {
                // Bad:
		// alert(error.message);
                // Better:
                dojo.byId("errors").innerHTML = 
                    "An error occurred while calculating data...";
	}
}

既存のツールを使う

ベスト・プラクティスとしては、NIH (Not Invented Here (ここで発明したものではない)) 症候群になることを極力避ける必要があります。既存のツール (フレームワークやプラットフォーム) を使うことで、それらのツールのリソースを活用することができます。成熟した一般的なツールの大部分は、パフォーマンスやブラウザー間の互換性に関して完全にテストされています。またそうしたツールは、独自のプロジェクトで時間をかけて実装する場合よりも、多くの機能を備えています。

Ajax 呼び出しを行うメソッドが用意された優れたツールの多くでは、他にも多くの関数や機能 (アニメーションなど) をサポートしています。それらのツールの一部を挙げたものが表 1 です。

表 1. Ajax 呼び出しを行うメソッドを備えた JavaScript ツール
ツール説明
Dojo ToolkitDojo Toolkit は無料で利用することができる JavaScript ツール・スイートです。Dojo Toolkit には、通常の Web ページへの Ajax 呼び出しのメソッドだけではなく、REST (Representational State Transfer) サービスへの Ajax 呼び出しのメソッドも用意されています。Dojo Toolkit のメソッドによってサポートされるメッセージ・フォーマットには、XML、JSON、プレーン・テキストがあります。
Google Web Toolkit (GWT) DesignerGoogle は最近、Instantiations Developer Tools を買収し、あらためて無料の製品スイートとして提供を開始しました。その 1 つが GWT Designer です。GWT Designer は既存の Eclipse システム上にインストールすることができます。GWT Designer を使用すると、GWT を使用するインターフェースを作成することができます。また GWT を使用すると、Ajax を使用する複雑な Web アプリケーションを作成することができ、ネイティブ・アプリケーションと同じくらい複雑な Web アプリケーションの作成が可能になります。RAP (Rich Ajax Platform) と同様、GWT は単なる JavaScript フレームワークではなく、むしろ Ajax 対応の HTML にコンパイル可能な、Java™ ベースのツールキットであると言うことができます。
jQueryjQuery も、Ajax の機能を完全に補完する JavaScript ライブラリーです。jQuery もさまざまなメッセージ・フォーマットをサポートしており、getScript() などの Ajax ベースのメソッドもサポートしています。getScript() は (「コンポーネントをプリロードする」というベスト・プラクティスに従って) JavaScript ファイルをダウンロードし、実行します。
PrototypePrototype も、Ajax 呼び出しを容易に行うための JavaScript フレームワークです。Ajax.PeriodicalUpdater などのメソッドを使用すると、Ajax ページの値を定期的に更新することができます。これを利用すれば、プログレス・バーや実行に時間がかかるサービス・プロセス用にステータスを表示するコントロールを実装することができます。
Rich Ajax Platform (RAP)

この表に挙げた他のフレームワークとは異なり、RAP は完全なプラットフォームです。RAP を使用すると、Swing アプリケーションや SWT (Standard Widget Toolkit) アプリケーションを作成する場合と同じように、Eclipse IDE (統合開発環境) と Java (JavaScript ではありません) コードを使って Ajax 対応の高度なサイトを作成することができます。HTML、CSS、JavaScript などの複雑なコードを扱いたくない Java プログラマーにとって、RAP のようなプラットフォーム・ツールが適切な選択肢になる場合があります。

RAP のドキュメントでは、既存の Eclipse システムのプラグインとして RAP をインストールしてはならないと警告しています。Eclipse のサイト (「参考文献」を参照) から Eclipse for RCP (Rich Client Platform) and RAP Developers のバンドルをダウンロードし、別の場所にインストールします。チートシートには、サンプル・プロジェクトのインポート方法が説明されています。


まとめ

Web アプリケーションに Ajax を使用すると、より滑らかな動作の Web アプリケーション・インターフェースを実現することができます。Ajax を使用することで、完全な HTML ページを送信する場合よりもある程度改善されますが、この記事で紹介したベスト・プラクティスを採用することで、より優れた Ajax アプリケーションを作成できるようになるはずです。

参考文献

学ぶために

  • Dojocampus.org を訪れ、Dojo Toolkit のサンプルや API のドキュメントを読んでください。
  • New to Web Development を訪れ、動的 Web アプリケーションその他について学んでください。

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

議論するために

コメント

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=594584
ArticleTitle=Ajax に関する 5 つのベスト・プラクティス
publish-date=11092010