芝生やDIY等のライフハックやWeb制作情報を発信するメディア

【順番も保証!】Ajaxで複数ファイルやページから取得した値を処理する方法

Web2018年4月4日

jQueryの$.ajax()を利用して別のページから要素を取得する際、取得先が1ページであればさほど問題はないのですが、複数ページから取得しかつ順序を保証して表示する場合はちょっとしたコツが必要です。個人的にハマったので、複数ページからの要素取得において順序を保証する実装方法のポイントをまとめてみました。

サンプルコード

3パターン、サンプルを用意してみました。

  • 順序が保証されないパターン(iが常に最大値かつ順序不定)
  • 順序が保証されないパターン(iは正しく処理されるも順序不定)
  • 順序が保証されるパターン

処理としては下記3ページのh1テキストを取得し、実行順序を検証用としてDOM生成しています。

以下のように表示されれば成功

  • (0)サイトについて
  • (1)お問い合わせ
  • (2)サイトマップ

では、それぞれのサンプルを見ていきたいと思います。

順序が保証されないパターン(iが常に最大値かつ順序不定)

HTML

<div class="hoge">
<ul class="list-bullet-01">
</ul>
</div>

js

$(function(){
  var $ajaxURLArr = [
    '/about/',
    '/contact/',
    '/sitemap/'
  ];
  for(var i = 0; i < $ajaxURLArr.length; i++){
    $.ajax({
      type:'GET',
      url:$ajaxURLArr[i],
      dataType:'html'
    })
    .then(
      /*読み込み成功時*/
      function(data){
        var $heading = $(data).find('h1.hdg-l1-01').find('span').text();
        var $headingDOM = '<li>(' + i + ')' + $heading +'</li>';
        $('.hoge ul.list-bullet-01').append($headingDOM);
      },
      /*読み込み失敗時*/
      function(){
        alert("読み込み失敗");
    });
  }
});
  • jQueryを読み込んでいる場合のスクリプトとなります

解説

以降のサンプル全て同様ですが、配列「$ajaxURLArr」に格納した3つのURLに対し、for文を回して$.ajax()で要素を取得します。取得した値は<li>(i)~</li>であらかじめ用意したhtmlにappend()します。

本サンプルの場合要素自体は取得できますが、DOM生成した変数iが全て最大値となってしまい、順序も不定になります。例えば、

  • (3)お問い合わせ
  • (3)サイトについて
  • (3)サイトマップ

だったり、

  • (3)サイトマップ
  • (3)お問い合わせ
  • (3)サイトについて

のように全ての要素に最大値「3」が付与され、表示順序も読み込みの度に不定となってしまいます。

順序が保証されないパターン(iは正しく処理されるも順序不定)

HTML

<div class="moge">
<ul class="list-bullet-01">
</ul>
</div>

js

$(function(){
  var $ajaxURLArr = [
    '/about/',
    '/contact/',
    '/sitemap/'
  ];
  for(var i = 0; i < $ajaxURLArr.length; i++){
    var $num = i;
    (function(i){
      $.ajax({
        type:'GET',
        url:$ajaxURLArr[i],
        dataType:'html'
      }).then(
        /*読み込み成功時*/
        function(data){
          var $heading = $(data).find('h1.hdg-l1-01').find('span').text();
          var $headingDOM = '<li>(' + i + ')' + $heading +'</li>';
          $('.moge ul.list-bullet-01').append($headingDOM);
        },
        /*読み込み失敗時*/
        function(){
          alert("読み込み失敗");
      });
    })($num);
  }
});
  • jQueryを読み込んでいる場合のスクリプトとなります

解説

前述の変数iが最大値になってしまう現象は、forで回す際$.ajax()を無名関数で囲い、変数$numにiを格納し、さらに無名関数に値を渡すことで解決できます。

ただ、番号は「0」「1」「2」と正しく付与されるものの相変わらず実行順序は不定なので、

  • (1)お問い合わせ
  • (0)サイトについて
  • (2)サイトマップ

だったり、

  • (2)サイトマップ
  • (1)お問い合わせ
  • (0)サイトについて

のように、やはり表示される順序は保証されません。

順序が保証されるパターン

前置きが長くなりましたが、こちらが表示順序が保証されるパターンです。

HTML

<div class="fuga">
<ul class="list-bullet-01">
</ul>
</div>

js

$(function(){
  var $ajaxURLArr = [
    '/about/',
    '/contact/',
    '/sitemap/'
  ];
  for(var i = 0; i < $ajaxURLArr.length; i++){
    $.ajax({
      type:'GET',
      url:$ajaxURLArr[i],
      dataType:'html',
      async:false
    })
    .then(
      /*読み込み成功時*/
      function(data){
        var $heading = $(data).find('h1.hdg-l1-01').find('span').text();
        var $headingDOM = '<li>(' + i + ')' + $heading +'</li>';
        $('.fuga ul.list-bullet-01').append($headingDOM);
      },
      /*読み込み失敗時*/
      function(){
        alert("読み込み失敗");
    });
  }
});
  • jQueryを読み込んでいる場合のスクリプトとなります

解説

一見最初のサンプルと変わりませんが、こちらは$.ajax()のオプションにasync:falseの記述を加えています。これによりデフォルトでの非同期ではなく同期での通信が実行され、ファイルの読み込み順が不動になり結果、実行順序が保証されるようになります。

$.ajax()を無名関数で囲う必要もありません。

デモ

実際に動作を確認できるデモページも公開しておりますのであわせてご確認ください。

まとめ

実装目的によって、非同期通信と同期通信を使い分けるとよいです。1ファイルなどであれば、わざわざ同期通信にする必要もありません。また、ご紹介したasync:falseによる同期通信にせずとも、$.when()メソッドを使って非同期通信のまま順番も保証して高速に処理する方法もあるようです。また時間があればサンプル作って検証してみたいと思います。

複数ファイルやページから取得した値を順番を保証して処理したい場合、どうぞ本記事がご参考になれば幸いです。

「Web」の他の記事を読む

ページの先頭に戻る