XMLHttpRequestの競合を起こしてしまっていた

こんなアホな事をする人が他にいるとは思わないけれど、あまりに自分に腹がたったのでメモ。


XMLHttpRequestを同時に複数行いたいときは、接続の数だけXMLHttpRequestをnewする必要がある。

//XXX これはバグコード
var request = new XMLHTTPRequest();

path1 = 'ごにょ';
path2 = 'ごにょごにょ';

request.open('GET', path1, true);
request.onreadystatechange = function() {
  if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
      //ごにょ
    }
  };
request.send(null);

request.open('GET', path2, true);
request.onreadystatechange = function() {
  if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
      //ごにょごにょ
    }
  };
request.send(null);

みたいなことはできない。これをやると通信の結果が上書きされたりして、バグがでる。
しかも、タイミング次第でいろいろな現象になるので、再現性の低い(知らない人にとっては)分かりにくいバグになる。

new XMLHTTPRequest();で作られるのは、接続してくれるエージェント(ブラウザ)ではなくて、接続の経路だということを覚えておこう。


したがって、上記の場合は

  var request1 = new XMLHTTPRequest();
  var request2 = new XMLHTTPRequest();
//以下略

としないといけない。


ただ、これは面倒なので

function simple_GET(path, callback){
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open('GET', path, true);
  xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
      callback(xmlhttp.responseText;);
    }
  };
  xmlhttp.send(null);
}

みたいなラッパーを作っておくと、simple_GET関数を呼ぶたびにローカル変数として、別の変数xmlhttpが作られるので楽になる。


ここまでは別に珍しくもない話。


ただ、今回俺はvar xmlhttpのvarを付け忘れて、xmlhttp = new XMLHttpRequest();としてしまっていた。
言うまでもなく、関数内でvarを付けないで変数を使うとグローバル変数として扱われるので、結局最初に紹介したバグケースと同じことをやってしまっていた。


なにしてるんだ俺...orz