非同期の要求
XMLHttpRequestオブジェクトのopen()メソッドで、async引数をfalseに設定した場合、send()メソッドで要求した結果がサーバーから完全に返されるまで制御が戻りません。これは、サーバーが長時間応答しない場合、問題になります。
そこで、通常の通信ではasyncをtrueに設定した非同期によるコンテンツのダウンロードが推奨されます。この場合、データの流れなどに多少の注意が必要になり、コードもsample00に比べるといくつかのステップが増えますが、サーバーからの応答を待たずにsend()メソッドを安全に終了することができます。
非同期による要求では、send()メソッドを呼び出すと、サーバーに要求を出した直後、サーバーからの応答を待たずにsend()メソッドからの制御が返ります。そのため、send()メソッドの直後にresponseTextを呼び出しても、データを取得していないために正しい結果を得ることができません。
非同期の場合、send()メソッドで要求したサーバーからの応答を別の関数で待機します。この関数はイベントハンドラのように機能し、サーバーからの応答があると自動的に呼び出されます。この待機用の関数はXMLHttpRequestオブジェクトのonreadystatechangeプロパティに設定しなければなりません。
attribute EventListener onreadystatechange;
onreadystatechangeに設定する関数は、引数を受けることはなく、戻り値も返しません。この関数が呼び出された時点で、XMLHttpRequestとサーバーがどの程度の通信を行っているのかを調べ、すべての作業が終了しているかどうかを確認します。
XMLHttpRequestには、非同期で要求を行っている場合に、サーバーとの通信がどの程度の段階にあるのかを表すreadyStateプロパティを用意しています。
readonly attribute unsigned short readyState;
readyStateの値は0~4番までが定められており、それぞれ次のような意味をもちます。
| 番号 | 意味 |
| 0 | 初期化されていない |
| 1 | open()メソッドが成功 |
| 2 | リクエストに成功 |
| 3 | HTTPヘッダを取得 |
| 4 | すべて完了 |
つまり、onreadystatechangeに設定した関数が呼び出され、かつXMLHttpRequestのreadyStateが4であれば、サーバーとの通信は完全に終了していると判断することができます。
これに加えて、コンテンツが存在しなかったり、サーバーに拒否された場合などのHTTP通信エラーを検出するにはstatusプロパティを使います。statusプロパティには、HTTPプロトコルで定められている応答コードが入ります。
readonly attribute unsigned short status;
例えば、指定したURLが見つからなかった場合に返される404などが有名です。成功した場合は200が返されるので、readyStateが4であり、statusが200であればダウンロードが成功したと判断することができます。これらが保証された時点でresponseTextやresponseXMLを使ってください。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="jp"> <head> <title>test</title> <script type="text/javascript"> var req; function requestText() { if ("XMLHttpRequest" in window) { req = new XMLHttpRequest(); } else if ("ActiveXObject" in window) { try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { req = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } req.open("GET", "test.txt", true); req.onreadystatechange = req_readystatechange; req.send(null); } function req_readystatechange() { var pLabel = document.getElementById("label"); if (req.readyState == 4) { if (req.status == 200) { pLabel.innerHTML = req.responseText; } else { pLabel.innerHTML = "読み込めませんでした"; } } } </script> </head> <body> <p id="label">読み込んだテキストがここに表示されます</p> <input type="button" value="ダウンロード" onclick="requestText()"/> </body> </html>
シンプルなAjaxのサンプルだったsample00に比べ、多少コードは複雑になってしまいましたが、これが標準的なAjaxベースのWebサイトを実現するための基本的な書き方となります。実行結果は、データを非同期で取得していることと、IE 6以下のバージョンでも動作することを除いてsample00と同じです。
