非同期の要求
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と同じです。