Ajaxオブジェクト

prototype.js解読のもう一つの山場。というか、ここが肝でしょうか。Ajax.Responders, Ajax.Base, Ajax.Request, Ajax.Updater, Ajax.PeriodicalUpdaterはそれぞれ別に解読します。

Ajaxオブジェクトは上記のAjax関連のクラス・オブジェクトの名前空間(他と名前の衝突を避ける)として使用されます。

基礎知識

ここで、初級者(=筆者^^;)のために、おさらい。

Ajaxとは、「Asynchronous JavaScript + XML」の略。「非同期(Asynchronous)なJavaScriptXMLを利用した技術」というような意味です。詳しくは>こちら<をご覧ください。

厳密な定義はともかく、一般的には「読み込こんだページはそのままに、更にサーバと通信してデータを取得し、ページの一部を更新する」というのがAjax、という感じになっています。

これを実現するのがJavaScriptXMLHttpRequestオブジェクトです。ページ上でサーバとの通信を担います。以下の例は意図的にシンプルにした例です。IE6.0のみで動作します。

ただし、読み込むファイル(test.txt)は文字コードUTF-8で記述してください。でないと文字化けします。WinXP付属のメモ帳でも保存時に文字コードの指定ができます。(参考:XMLHttpRequestのresponseTextで扱える文字コードについて - Backstage of theater.js)

【参考】
[test.htm]
<html>
<head>
<title></title>
<script language="javascript">
<!--
var req = null;
function test(){
  req = new ActiveXObject("MSXML2.XMLHTTP"); 
                                     //XMLHttpRequestオブジェクト作成(IE6のみ)

  req.onreadystatechange = write;    //onreadystatechangeに実行する関数を設定
                                     //関数は通信状況が変化した際に実行される

  req.open('GET', 'test.txt', true); //URL等を設定

  req.send('');                      //送信

}

function write(){          //通信状況が変化した際に実行される関数
  
  if(req.readyState == 4){ //readyStateプロパティが4(受信完了)であれば処理する

	document.getElementById('test').innerHTML = req.responseText;
                           //responseTextプロパティを画面に書き込む
  }
}
//-->
</script>
</head>
<body>
<div id="test"></div>
<button onclick="test();">TEST</button>
</body>
</html>
---------------------------------------------------------
[test.txt]このファイルを同一ディレクトリに用意。UTF-8で記述すること。
Ajax(XMLHttpRequest)のテスト

「サーバと通信」と書きましたが、ローカルでも動作します。TESTボタンを押すと、「Ajax(XMLHttpRequest)のテスト」という文字列が表示されます。

非常に簡単に説明すると、

  • XMLHttpRequestオブジェクトを作成
  • onreadystatechangeプロパティに実行する関数を指定。
  • openメソッドでURL等を設定。
  • sendメソッドで送信。
  • onreadystatechangeプロパティに設定した関数内で、readyStateプロパティが4(受信完了)の場合に、responseTextプロパティ等から受信データを取得。
  • あとはお好きにw

という流れになります。

実際はブラウザの違いを吸収する等、他にも処理が必要です。これを実装し、機能追加したのがprototype.jsAjaxオブジェクト(および配下のクラス・オブジェクト)といえます。上の例をprototype.jsで書き直すとこうなります。

【参考】
<html>
<head>
<title></title>
<script language="javascript" src="prototype.js" charset="utf-8"></script>
<script language="javascript">
<!--
function test(){
  new Ajax.Updater('test', 'test.txt', {method:'get'});
}
//-->
</script>
</head>
<body>
<div id="test"></div>
<button onclick="test();">TEST</button>
</body>
</html>

なお、AjaxXMLHttpRequestについての詳しい(正しい?)説明は他のサイトを参照してください・・・。

解読

【抜粋】
var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      function() {return new XMLHttpRequest()}
    ) || false;
  },

  activeRequestCount: 0
}

Ajaxオブジェクトを作成しています。ここではメソッドとプロパティが一つずつ定義されていますが、以降で更に追加されます。*1

getTransportメソッド

前述の「基礎知識」で提示した例は、NetscapeやOpreaでは動作しません。これはブラウザによってXMLHttpRequestオブジェクトの取得方法が異なるためです。この差を吸収するためのメソッドがgetTransportです。

Try.theseメソッドによりXMLHttpRequestオブジェクトの取得を試み、取得できたものを返却しています。上から順に、IE6、IE5.5以前、他のブラウザのXMLHttpRequestオブジェクト取得用関数です。取得できなかった場合はfalseを返却します。

activeRequestCountプロパティ

activeRequestCountは現在処理中のリクエストの数を格納しています。

XMLHttpRequestオブジェクトによる通信は、同時に複数行うことが可能です。これが非同期(Asynchronous)といわれる所以です。

以下の例は、Ajax.activeRequestCountが2以上の状態を作りたいがために、サーバサイドでJSPを使いました。

【例】
[test.htm]
<html>
<head>
<title></title>
<script language="javascript" src="./prototype.js" charset="utf-8"></script>
<script language="javascript">
<!--
function test(){
  new Ajax.Request(
    'test.jsp', 
    { method: 'get',
      onComplete:function(req){
        $('test').innerHTML += req.responseText + ":" + Ajax.activeRequestCount;
      }
    });
}
//-->
</script>
</head>
<body>
<div id="test"></div>
<button onclick="test();test();">TEST</button>
</body>
</html>
---------------------------------------------------------
[test.jsp]
<%@ page contentType="text/plain;charset=utf-8" %>
<%@ page import="java.util.*, java.io.*" %>
<%
//キャッシュ無効化
Calendar today = new GregorianCalendar();
response.setDateHeader("Last-Modified", today.getTime().getTime());
response.setDateHeader("Expires", 0);
response.setHeader("Pragma","no-cache");
response.setHeader("Cache-Control","no-cache");
//2秒待つ
Thread.sleep(2000);
%>
Ajax(XMLHttpRequest)のテスト

htmのボタンを押すと、以下が表示されます。(タイミングによっては違う場合もあります^^;)

【上記例の実行結果】
Ajax(XMLHttpRequest)のテスト :2 Ajax(XMLHttpRequest)のテスト :1

断りなくAjax.Request、サーバサイドのJSPを例に使ってしまいました。Ajax.Requestの説明は以降で行います。JSPは環境(JAVAApache等)がないと動作しません。筆者の経験言語・環境により、現在使えるのがJSPくらいなので、以降サーバサイドの例が必要な場合はJSPを使用します。本当はPHPRubyがいいのでしょうけど・・・。

*1:追加される、といっても名前空間として使用されるだけで、プロパティやメソッドが追加されるわけではないです。。。