getElementById()を計ってみる

なんとなく遅いと思っているgetElementById()だけど、「なんとなく」はよくないな…と思って計ってみる。

テストコード

この日記をローカルに保存して、テストコードを埋め込んだ。
しかし、どう見ても差がつきそうな気が…

<script type="text/javascript">
  function no_cache() {
    var tab_name_list = new Array();
    var tag_name = null;

    for(var i = 0; i < 10000; i++) {
      tag_name = document.getElementById('targer_element').tagName;
      tab_name_list.push(tag_name);
    }
  }

  var elements = {};

  function cached() {
    var tab_name_list = new Array();
    var tag_name = null;
    elements['targer_element'] = document.getElementById('targer_element');

    for(var i = 0; i < 10000; i++) {
      tag_name =  elements['targer_element'].tagName;
      tab_name_list.push(tag_name);
    }
  }
</script>
(中略)
<input type="button" value="キャッシュなし" onclick="Profiler.profile('no cache', no_cache);">
<input type="button" value="キャッシュあり" onclick="Profiler.profile('cached', cached);">
<input type="button" value="レポート" onclick="Profiler.report();">

結果

テストはIE6で実施。

                                                    • -

Microsoft Internet Explorer

                                                    • -
    • -

name: no cache
count: 5
duration: 1809.6 [ms]

    • -

name: cached
count: 5
duration: 90.4 [ms]

                                                    • -

OK

                                                    • -

まあ、そりゃあ差は出るよね…
ただ、相対的には遅いけど、絶対的な速度で問題になるかはよくわからないなぁ。

Profiler

Profilerはこんな感じ。
Ajaxイン・アクション」を参考にするつもりだったけど、サンプルコードがあまりにコードが酷すぎたので自作。

Profiler = new Object();

Profiler.watches = new Object();

Profiler.start = function(name) {
  var watch = Profiler.watches[name];

  if (!watch) {
    watch = new Array();
    watch.avg = function() {
      var sum = 0;
      for(var i = 0; i < watch.length; i++) { sum += watch[i]; }
      return (sum / watch.length);
    }

    Profiler.watches[name] = watch;
  }

  var start = new Date();

  return function() {
    var stop = new Date();
    var duration = stop - start;
    watch.push(duration);
  };
}

Profiler.profile = function(name, transaction) {
  var stop = Profiler.start(name);
  transaction();
  stop();
}

Profiler.report = function() {
  var name = null;
  var watch = null;
  var report = new Array();

  for(name in Profiler.watches) {
    watch = Profiler.watches[name];
    report.push('---');
    report.push('name: ' + name);
    report.push('count: ' + watch.length);
    report.push('duration: ' + watch.avg()+ ' [ms]');
  }

  alert(report.join('\n'));
  Profiler.watches = new Object();
}