[jQuery+PHP] Ajax で連動プルダウンを作る方法と高速化

2019-08-31JavaScriptAjax, jQuery, 高速化

プルダウン A で選択された値を元にサーバーで検索した結果を、プルダウン B の選択肢( option タグ)に追加し連動するプルダウンを作る。プルダウン A で選択された値は Ajax で PHP に送り、 PHP 側で DB 検索した結果を返し、 jQuery で option タグに追加していく。
このとき option タグ生成の速い方法を調べた。

スポンサーリンク

連動プルダウンを作る方法

サンプルコード。

画面( HTML + PHP )

<label for="aaa">プルダウン A : </label>
<select name="a" id="aaa">
  <option selected disabled>未選択</option>
<?php 
$res = $mysqli->query("SELECT id, name FROM test");
while( $data = $res->fetch_assoc() ) {  ?>
  <option value="<?=$data['id']?>"><?=$data['name']?></option>
<?php } ?>
</select>
  
<label for="bbb">プルダウン B : </label>
<select name="b" id="bbb">
</select>

jQuery

$("#aaa").on('change', function(){
    var aVal = $(this).val();

    $.ajax({
      type: "POST",
      url: "hoge.php",
      data: { "aaa" : aVal },
      dataType : "json"
    }).done(function(data){
      // map で option タグのオブジェクトを生成しておいて、ループの外で append する
      var arr = $.map(data, function (val, index) {
          $option = $('<option>', { value: index, text: val});
          return $option;
      });
      $('#bbb').append(arr);
    }).fail(function(XMLHttpRequest, textStatus, error){
      alert("エラーが発生しました。);
    });
  });
});

hoge.php ( Ajax から呼ばれて DB 検索する)

$aaa = filter_input(INPUT_POST, "aaa");

// DB から検索する処理
$stmt=$mysqli->prepare("SELECT id, bbb FROM tableb WHERE aaa = ?");
$stmt->bind_param(str_repeat('s', $aaa);
$stmt->execute();
$res = $stmt->get_result();

$list = array();
while( $data = $res->fetch_assoc() ) {
  $list[$data['id']] = $data['bbb'];
}
header('Content-Type: application/json');
echo json_encode($list);

option タグ生成の方法と速度

高速化について調べたところ以下の情報を見つけた。

  • DOM へのアクセスは、 id 指定が速い
  • ループは for...in が遅い。( for が最速らしい)
  • DOM へのアクセス回数は少ない方がいい → この場合 $.mapoption タグの配列を作って、ループの外で append するのがいいらしい

以上を踏まえて 3 つの方法の速度を測ってみた。

方法 1 $.each

$.each(data, function(index, val) {
  $('#bbb').append($('<option>').text(val).attr('value', index));
})

方法 2 $.map

var arr = $.map(data, function (val, index) {
  $option = $('<option>', { value: index, text: val});
  return $option;
});
$('#bbb').append(arr);

方法 3 for...in

for (var key in data){
  $('#bbb').append($('<option>').text(data[key]).attr('value', key));
}

速度測定

それぞれを関数にしてひとつづつ、 console.time() で計測した。

  • PC : Mac
  • OS : Amazon Linux
  • ブラウザ : Chrome
var array = {'a1':'あいうえお', 'a2':'かきくけこ', 'a3':'さしすせそ', 'a4':'たちつてと', 'a5':'なにぬねの', 'a6':'はひふへほ', 'a7':'まみむめも', 'a8':'やゆよ', 'a9':'アイウエオ', 'a10':'0123456789'};

console.time("time");
test1(array);
console.timeEnd("time");

function test1(data) {
  $.each(data, function(index, val) {
    $('#bbb').append($('<option>').text(val).attr('value', index));
  })
}

function test2(data) {
  var arr = $.map(data, function (val, index) {
      $option = $('<option>', { value: index, text: val});
      return $option;
  });
  $('#bbb').append(arr);
}

function test3(data) {
  for (var key in data){
    $('#bbb').append($('<option>').text(data[key]).attr('value', key));
  }
}

5 回実行してみた。

test1 (方法 1 $.each )

time: 3.743896484375ms
time: 2.001953125ms
time: 1.803955078125ms
time: 2.02197265625ms
time: 0.89306640625ms

test2 (方法 2 $.map )

time: 3.8740234375ms
time: 1.425048828125ms
time: 0.498046875ms
time: 1.10302734375ms
time: 0.572021484375ms

test3 (方法 3 for…in )

time: 3.84814453125ms
time: 1.64404296875ms
time: 1.942138671875ms
time: 2.273193359375ms
time: 1.72705078125ms

結果
$.map が速そう。
5 回分の計測結果だけど、何度もやってみるとあまり変わらなかった。件数が多いともっと変わってくるのかもしれないけど。

Posted by Agopeanuts