MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

同期および非同期リクエスト

XMLHttpRequest は同期および非同期通信をサポートしています.しかし,一般にパフォーマンス上の理由により非同期リクエストが同期リクエストより選好されるべきです.

手短かにいえば,同期リクエストはプログラムの実行をブロックし.画面の「フリーズ」やユーザーインターフェイスの無反応状態を生み出します.

非同期リクエスト

機能拡張(extension)からXMLHttpRequestを利用するのであれば,それは非同期でなければなりません.この場合,データを受信した時点でコールバックを受取ることになります.そのためリクエストが取扱われている間ブラウザは普通に動作することができます.

例: コンソールログへファイルを送信する

最も簡単な非同期XMLHttpRequestの使用法を示します.

var xhr = new XMLHttpRequest();
xhr.open("GET", "/bar/foo.txt", true);
xhr.onload = function (e) {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      console.log(xhr.responseText);
    } else {
      console.error(xhr.statusText);
    }
  }
};
xhr.onerror = function (e) {
  console.error(xhr.statusText);
};
xhr.send(null); 

リクエストが非同期に取扱われるべきことを指示するため.行2で第3引数に true を指定しています.

行3はイベントハンドラ関数オブジェクトを生成し,リクエストのonload属性にアサインしています.このハンドラは,行4でトランザクションが完了したかどうかを知るためリクエストのreadyStateを監視し,完了済み,かつHTTPステータスが200なら受信内容をコンソール出力します.エラー発生時にはエラーメッセージが表示されます.

行15は実際にリクエストを開始します.コールバックルーチンは,リクエストの状態が変更される都度呼び出されます.

例: 外部ファイルを読込む標準的な関数を作成する

場合によっては,多くの外部ファイルを読込まねばなりません.これは読込まれたファイルの内容を指定されたリスナに切換えるためにXMLHttpRequestオブジェクトを非同期に利用する標準的な関数です.

function xhrSuccess () { this.callback.apply(this, this.arguments); }

function xhrError () { console.error(this.statusText); }

function loadFile (sURL, fCallback /*, argumentToPass1, argumentToPass2, etc. */) {
  var oReq = new XMLHttpRequest();
  oReq.callback = fCallback;
  oReq.arguments = Array.prototype.slice.call(arguments, 2);
  oReq.onload = xhrSuccess;
  oReq.onerror = xhrError;
  oReq.open("get", sURL, true);
  oReq.send(null);
}

使用法 :

function showMessage (sMsg) {
  alert(sMsg + this.responseText);
}

loadFile("message.txt", showMessage, "New message!\n\n");

行1ではファイルが読込まれた時点で,第3引数以降の全引数をcallback関数に渡す関数を宣言しています

45ではイベントハンドラ関数オブジェクトを生成し,リクエストのonload属性にアサインしています.このハンドラはトランザクションが完了したことを知るため,リクエストのreadyStateを監視します.トランザクションが完了し,かつ,HTTPステータスコードが200ならコールバック関数が呼び出されますエラーが発生すれば,エラーメッセージが表示されます.

1311ではリクエストを非同期に取扱うべきことを指示すため第3引数にtrueを指定しています.

1412で実際にリクエストを開始しています.

例: タイムアウトの利用

読込みが行なわれるのを待つ間,プログラムが永久にハングすることを防ぐためタイムアウトを利用できます.以下のコードに示すように,XMLHttpRequestオブジェクト上のtimeoutプロパティの値を設定することで行なわれます

  var args = arguments.slice(2);
  var xhr = new XMLHttpRequest();
  xhr.ontimeout = function () {
    console.error("The request for " + url + " timed out.");
  };
  xhr.onload = function() {
    if (xhr.readyState === 4) { 
      if (xhr.status === 200) {
        callback.apply(xhr, args);
      } else {
        console.error(xhr.statusText);
      }
    }
  };
  xhr.open("GET", url, true);
  xhr.timeout = timeout;
  xhr.send(null);
}

ontimeout ハンドラをセットすることで「タイムアウト」イベントを取扱うコードを追加していることに留意して下さい.

使用法:

function showMessage (sMsg) {
  alert(sMsg + this.responseText);
}

loadFile("message.txt", 2000, showMessage, "New message!\n");

ここではタイムアウトを2000ミリ秒に設定しています.

注記: timeoutのサポートは Gecko 12.0において追加されました.

同期リクエスト

稀ではありますが,同期法の利用が非同期法より望ましいことがあります.

例: HTTP 同期リクエスト

本例では簡単な同期リクエストをどのように生成するのかを示します.

var request = new XMLHttpRequest();
request.open('GET', '/bar/foo.txt', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {
  console.log(request.responseText);
}

行3でリクエストを送信しています.null引数はGETリクエストにボディコンテントが必要ないことを示しています.

行5ではトランザクション完了後,ステータスコードをチェックしています.結果のコードが200(HTTPのOK)ならドキュメントのテキスト内容がコンソール出力されます.

例: Workerからの同期HTTPリクエスト

同期リクエストが通常,コード実行をブロックしない稀な例として,Worker内でのXMLHttpRequestの利用があります.

example.html (主ページ):

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
  var worker = new Worker("myTask.js");  
  worker.onmessage = function(event) {  
    alert("Worker said: " + event.data);
  };

  worker.postMessage("Hello");
</script>
</head>
<body></body>
</html>

myFile.txt (XMLHttpRequest同期呼出しのターゲット):

Hello World!!

myTask.js ( Workerです):

self.onmessage = function (event) {
  if (event.data === "Hello") {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "myFile.txt", false);  // 同期リクエスト
    xhr.send(null);
    self.postMessage(xhr.responseText);
  }
};
注記: しかしながらWorkerを使っているため効果は非同期になります.

それはサーバーとバックグラウンドでやり取りしたり,コンテントを予めロードしたりするので有用でしょう.例と詳細については Using web workers を参照下さい.

同期リクエストでなければならない場合

XMLHttpRequestを同期的に使用するしかない場合があります.例えば,これはwindow.onunloadwindow.onbeforeunloadイベントの間に起こります.(下記も参照).

ページがアンロードされた時点で通常のXMLHttpRequestを送信することは,サーバーからの非同期レスポンスに付随する問題を招きます:レスポンスが返って来るまでに,ページはアンロード済みで,コールバック関数はもはや存在しません.これはJavaScriptの “function is not defined”エラーを生み出します.

A possible solution is to make sure that any AJAX requests that you make on unload are make synchronously instead of asynchronously. This will ensure that the page doesn’t finish unloading before the server response comes back.

例#1:exit前の自動ログアウト

window.onbeforeunload = function () {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "logout.php?nick=" + escape(myName), false);  // 同期リクエスト
  xhr.send(null);
  if (xhr.responseText.trim() !== "logout done"); {  // "logout done" は期待されるレスポンステキストです
    return "Logout has failed. Do you want to complete it manually?";
  }
};

例 #2: ユーザーがリンクをクリックすることも退屈なベージを登録することもなくサイトを去る場合,注意すること

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
(function () {

  function dontPanic () {
    bForsake = false;
    return true;
  }

  onload = function () {
    for (
      var aLinks = document.links, nLen = aLinks.length, nIdx = 0;
      nIdx < nLen;
      aLinks[nIdx++].onclick = dontPanic
    );
  };

  onbeforeunload = function () {
    if (bForsake) {
      /* silent synchronous request */
      var oReq = new XMLHttpRequest();
      oReq.open("GET", "exit.php?leave=" + escape(location.href), false);
      oReq.send(null);
    }
  };

  var bForsake = true;

})();
</script>
</head>
 
<body>

<p><a href="https://developer.mozilla.org/">Example link</a></p>

</body>
</html>

See also

ドキュメントのタグと貢献者

 このページの貢献者: hamasaki, acid
 最終更新者: acid,