JS memo

お洒落にJavaScript。

2019年2月10日12:02

javascriptのxhrを複数利用する時のエラーの解決策

メインビジュアル

javascriptのxhrを複数利用する時のエラーの解決策

複数URLのデータを読み込むためにXMLHttpRequestをforループ内で使用すると、上手くいかなかったので、その時の対処法を記録します。

※XMLHttpRequestの実装方法はコチラをご覧ください。

    目次

  1. エラーが発生した経緯
  2. エラーの原因
  3. 解決方法
  4. まとめ

エラーが発生した経緯

サイト内の検索エンジンを作成する際に、複数ページをXMLHttpRequestとforループで読み込むよう以下のように設定しました。

const urlLists = ["/data/xml/", "/site-speed/asynchronous/","/site-speed/for_while/","/site-speed/async-2/","/fix-error/js-error-2/","/fix-error/js-error-1/","/data/array-method/","/framework/jquery-1/"];
for( urlList of urlLists ){
  let xhr = new XMLHttpRequest();
  xhr.open("GET", urlLists, true);
  xhr.send();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      // キーワードがページ内にあるか確認するコード
    }
  };
}

しかし同じキーワードで検索した際に、毎回検索結果が変わると言う謎の現象が起き、上手く作動しませんでした。

エラーの原因

どうやら、onreadystatechangeがreadyStateが4になるまで待っている間に、forループが次のループにいってしまっていたようです。

解決方法

2つの解決策を発見したので、ご紹介いたします。

1.再帰関数を使用する

forループは使用せずに、キーワードを探すページの数だけ、再帰関数で呼び出すようにしました。

const urlLists = ["/data/xml/", "/site-speed/asynchronous/","/site-speed/for_while/","/site-speed/async-2/","/fix-error/js-error-2/","/fix-error/js-error-1/","/data/array-method/","/framework/jquery-1/"];
let searchKeyword = (cnt) => {
  let xhr = new XMLHttpRequest();
  xhr.open("GET", urlLists, true);
  xhr.send();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      // キーワードがページ内にあるか確認するコード
      if( cnt < urlLists.length-1 ) {
        searchKeyword(cnt+1);
      }
    };
}
searchKeyword(0);

上記ではfunction(searchKeyword)を作成、その中でXMLHttpRequestを扱っています。その中で

if( cnt < urlLists.length-1 ) { searchKeyword(cnt+1);}

をonreadystatechange内に付け足すことで、処理が終わってから、searchKeywordをページの数分実行してねと指示しています。

2.もはやjQureyで実装する

今回のエラーの問題点はforループのループ速度がXMLHttpRequestの処理より早すぎて、前のループが上書きされてしまうことでした。

そのため、下記のようにjQueryのajaxをeachでループしてあげることで、それぞれの内容が上書きされずに並列処理されます。

const urlLists = ["/data/xml/", "/site-speed/asynchronous/","/site-speed/for_while/","/site-speed/async-2/","/fix-error/js-error-2/","/fix-error/js-error-1/","/data/array-method/","/framework/jquery-1/"];
$.each(urlLists, function(i){
  $.ajax({
     url : urlLists[i],          
     dataType : 'html',
     success : function(data){
        // キーワードがページ内にあるか確認するコード
      },
     error: function(data){
       console.log("error")
      }
    });
});

ただ、ajaxは上書きされませんが、同時に処理を行います。そのめため、結果の順番が速いもの順になるので注意が必要です。

まとめ

XMLHttpRequestはリクエストを送信して、レスポンスを受けるまで待つ処理が生じます。

そのため、複数使用する場合にはエラーが発生しやすいので、前の処理が終わってから次の処理を行うよう実装する際に工夫が必要です。

順番を気にしない場合はjQueryで簡単に実装できるので、状況によって使い分けましょう!