2014年3月23日日曜日

jQuery高速化コーディングテクニック

コードの書き方ひとつでjQueryを使用したアプリは劇的に高速になります。
高速化の効果が特に高かったコーディング方法をメモしておきます。

※今回使用したブラウザ
Chromium バージョン 32.0.1700.107 Ubuntu 13.10

セレクタでDOMを取得するとき


IDを指定する
できるだけIDを指定します。
例: $("#div1")

セレクタはシンプルに
できるだけセレクタはシンプルにします。

遅い: $(".class1 .class2 .class3")
速い: $(".class3") 約4倍高速

メソッドを使う
遅い: $("div:eq(0)")
速い: $("div").eq(0) 約20倍高速


スタイルを指定するとき


css()をメソッドチェーンで使う

遅い:
elem.css("color", "black");
elem.css("background-color", "white");

普通:
elem.addClass("myclass");
約3倍高速

速い:
elem
  .css("color", "black")
  .css("background-color", "white");
約10倍高速


属性を指定するとき


attr()をメソッドチェーンで使う

遅い:
elem.attr({
  "alt": "hoge",
  "title": "foo"
});

普通:
elem.attr("alt", "hoge");
elem.attr("title", "foo");
約10倍高速

速い:
elem
  .attr("alt", "hoge")
  .attr("title", "foo");
約20倍高速


data属性を指定するとき


$.data()を使う

遅い:
elem.data("key", "value")
速い:
$.data(elem, "key", "value")
約2倍高速


ループ処理


$.each よりも JSネイティブな for を使う
[JavaScript]最速の配列ループ処理


実験に使ったコード
<meta charset="utf-8"></meta>
<style type="text/css">
.myclass {
  color: black;
  background-color: white;
  border:1px solid black;
}
</style>
<!--script src="lib/js/jquery-2.1.0.min.js"></script-->
<script src="https://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript">
$(function() {

  /* ===================================
   *  get element by selector
   * ==================================*/

  var elem = null;
  console.log("-- Get element by selector --");

  // by specified id
  console.time("$('#divI')");
  elem = $("#divI");
  console.timeEnd("$('#divI')");

  // by detailed classname
  console.time('$(".class0 .class1 .class2 .class3")[2]');
  elem = $(".class0 .class1 .class2 .class3")[2];
  console.timeEnd('$(".class0 .class1 .class2 .class3")[2]');

  // by simple classname   
  console.time('$(".class3")[8]');
  elem = $(".class3")[8];
  console.timeEnd('$(".class3")[8]');

  // by method
  console.time('$(".class3").eq(8)');
  elem = $(".class3").eq(8);
  console.timeEnd('$(".class3").eq(8)');

  // by complex selector   
  console.time('$(".class3:eq(8)")');
  elem = $(".class3:eq(8)");
  console.timeEnd('$(".class3:eq(8)")');


  /* ===================================
   * apply styles
   * ==================================*/

  console.log("-- styles --");
  console.time("addClass('myclass')");
  elem.addClass('myclass');
  console.timeEnd("addClass('myclass')");

  console.time("css() separately");
  elem.css("color", "black");
  elem.css("background-color", "white");
  elem.css("border", "1px solid black");
  console.timeEnd("css() separately");

  console.time("css({...})");
  elem.css({ 
    "color": "black",
    "background-color": "white",
    "border": "1px solid black"
  });
  console.timeEnd("css({...})");

  console.time("css().css()...");
  elem
    .css("color", "black")
    .css("background-color", "white")
    .css("border", "1px solid black");
  console.timeEnd("css().css()...");

  /* ===================================
   * use data attribute
   * ==================================*/

  console.log("-- data attribute --");
  console.time("$.data()");
  $.data(elem, "key1", "value1");
  console.timeEnd("$.data()");

  console.time("elem.data()");
  elem.data("key1", "value1");
  console.timeEnd("elem.data()");


  /* ===================================
   * use attribute 
   * ==================================*/

  console.log("-- attribute --");
  console.time("attr({...})");
  $("#img0").attr({
    'title': 'http://mysite.com/images/image.jpg',
    'alt': 'My Image'
  });
  console.timeEnd("attr({...})");

  console.time("attr() separately");
  $("#img0").attr('title', 'http://mysite.com/images/image.jpg');
  $("#img0").attr('alt', 'My Image');
  console.timeEnd("attr() separately");

  console.time("attr().attr()...");
  $("#img0")
    .attr('title', 'http://mysite.com/images/image.jpg')
    .attr('alt', 'My Image');
  console.timeEnd("attr().attr()...");

});
</script>
<img id="img0"></img>
<div class="class0">
  <div class="class1">
    <div class="class2">
      <div id="divA" class="class3">A</div>
      <div id="divB" class="class3">B</div>
      <div id="divC" class="class3">C</div>
    </div>
  </div>
  <div class="class1">
    <div class="class2">
      <div id="divD" class="class3">D</div>
      <div id="divE" class="class3">E</div>
      <div id="divF" class="class3">F</div>
    </div>
  </div>
  <div class="class1">
    <div class="class2">
      <div id="divG" class="class3">G</div>
      <div id="divH" class="class3">H</div>
      <div id="divI" class="class3">I</div>
    </div>
  </div>
</div>

実行結果
-- Get element by selector -- 
$('#divI'): 0.158ms
$(".class0 .class1 .class2 .class3")[2]: 0.621ms
$(".class3")[8]: 0.157ms
$(".class3").eq(8): 0.156ms
$(".class3:eq(8)"): 2.960ms

-- styles -- 
addClass('myclass'): 0.297ms
css() separately: 0.933ms
css({...}): 0.167ms
css().css()...: 0.099ms

-- data attribute --
$.data(): 0.458ms
elem.data(): 0.758ms

-- attribute --
attr({...}): 0.723ms
attr() separately: 0.052ms
attr().attr()...: 0.030ms


まとめ

できるだけメソッドチェーンを使うべし。
メンテナンス性を考えると、スタイルの操作に addClass() / removeClass() を使うのも悪くないと思いますが、処理スピードを重視する場面ではメソッドチェーンを使うのがベスト。

0 件のコメント:

コメントを投稿