LoginSignup
305
308

More than 5 years have passed since last update.

jQueryのパフォーマンスを下げるアンチパターンに関する超意訳

Posted at

以下のスライドを意訳したものです。Compress周りについては触れていません。「いやいや、最新の書き方だともっと良い書き方があるんだよ!」という方のコメントをお待ちしております!
http://www.slideshare.net/paul.irish/perfcompression

クエリをキャッシュする

// 悪い例
var id = $("#content").data("id");
var itemId = $("#content").data("item-id");

// 良い例
var content = $("#content")
var id = content.data("id");
var itemId = content.data("item-id");

HTMLを生成するときにjQueryオブジェクトにアクセスし続けない

// 悪い例
$.each(reallyLongArray, function(count, item) {
  var newLi = '<li>' + item + '</li>';
  $('#ballers').append(newLi);
});

// 良い例 : DocumentFragmentを使用
var frag = document.createDocumentFragment();
$.each(reallyLongArray, function(count, item) {
  var newLi = '<li>' + item + '</li>';
  frag.appendChild(newLi[0]);
});
$('#ballers')[0].appendChild(frag);

// 良い例 : Stringを使用
var myhtml = "";
$.each(reallyLongArray, function(count, item) {
  myhtml += '<li>' + item + '</li>';
});
$('#ballers').html(myhtml);

Keep things DRY

// 悪い例
if ($ventfade.data('currently') != 'showing') {
  $ventfade.stop();
}
if ($venthover.data('currently') != 'showing') {
  $venthover.stop();
}
if ($spans.data('currently') != 'showing') {
  $spans.stop();
}

// 良い例
var elems = [$ventfade, $venthover, $spans];
$.each(elems, function(k, v){
  if (v.data('currently') != 'showing') {
    v.stop();
  }
});

アンチパターン:オブジェクトリテラルを使わない宣言

無名関数で定義されているせいで、どこで何が起こっているのか判断がつかなくなってしまうケース。

$(document).ready(function() {
  ...
  $('#magic').click(function(e) {
    $('#yayeffects').slideUp(function() {
      ...
    });
  });
  $('#happiness').load(url + ' #unicorns', function() {
    ...
  });
});

オブジェクトリテラルを使用して記述するようにする。

var PI = {
  onReady: function() {
    ...
    $('#magic').click(PI.candyMtn);
    $('#happiness').load(url + ' #unicorns', PI.unicornCb);
  },
  candyMtn: function(e) {
    $('#yayeffects').slideUp(PI.slideCb);
  },
  slideCb: function() {
    ...
  },
  unicornCb: function() {
    ...
  }
};

オブジェクトリテラルを使用することで、下記の利点を得られる。

  • コードの見通しがよくなる。
  • プロファイラで関数名を参照できる。
  • 各関数をコンソールで実行してみることができる。
  • 無名関数のときと比べて、テストが書きやすくなる。

アンチパターン:再クエリ

// create and append your element
$(document.body).append('<div class="baaron" />');
// requery to bind stuff
$("div.baaron").click(function(){  });

// better
// swap to appendTo to hold your elem
$('<div class="baaron" />')
  .appendTo(document.body)
  .click(function(){  });

$('#whats .the', context)

// パフォーマンスはこっちよりも
var arms = $('div.robotarm', '#container');
// こっちの方がいい
var arms = $('#container').find('div.robotarm');

// 読みやすさ的にはcontext?好みの問題かも。。

セレクタのパフォーマンス最適化

一番パフォーマンスが良いのは#idから下降する書き方。

// 普通の書き方
var arms = $('#container div.robotarm');
// もっと良い書き方
var arms = $('#container').find('div.robotarm');

不必要なセレクタを挟まないほうが、より高速にヒットする。

// 余計なものが混じっている
.data table.attendees td.gonzalez
// 中間をはぶこう
.data td.gonzalez

ユニバーサルセレクタはパフォーマンスを劣化させる。明示的に書いていなくても、暗黙のユニバーサルセレクタが使われている場合があるので、注意すること。

$('.buttons > *') // 超コストがかかる
$('.buttons').children() // 良い例

$('.gender :radio') // 暗黙のユニバーサルセレクタが含まれている
$('.gender *:radio') // 上記と同じ意味になる
$('.gender input:radio') // 良い例

効率的なCSSの書き方(https://developer.mozilla.org/ja/Writing_Efficient_CSS)

イベントのデリゲート

live()を使うより、delegate()を使うことでより高速化できる。

// 汚い書き方。。
$('a.trigger', $('#container')[0]).live('click', handerFn);

// 良い書き方
$('#container').delegate('click', 'a.trigger', handlerFn);

DOMの操作は総じて重い

タグのスタイル属性を直接操作するのはもってのほか。スタイルをいじりたい場合はクラスを変えよう。(DOMの操作は最小限におさえるのが原則)

ブラックボックスとしてjQueryを扱わない

単にjQueryを隠蔽する書き方は、単に可読性を下げるだけだ。

// これでは単にjQueryを隠蔽しているだけで、無駄にメソッドを増やしていだけに過ぎない。。
getScript: function( url, callback ) {
  return jQuery.get( url, null, callback, "script" );
},
getJSON: function( url, data, callback ) {
  return jQuery.get( url, data, callback, "json");
},

よく使うメソッドは覚えておこう。

map(), slice(), stop(), (de)queue(), prevAll(), pushStack(), inArray(), etc…

// index() in jQuery <= 1.3.2
$('#rdworth').parent().children().index( $('#rdworth')[0] )

// prevAll()を使うと10%速くなる
$('#rdworth').prevAll().length

// jQuery1.4からはこう書ける
$('#rdworth').index()

存在しない要素に対するアクションを書かないこと

jQueryは凄く空気を読んでくれるので、そんなコードを書いたとしてもエラーは出さない・・・けど、ものすごいオーバーヘッドが裏で生じることになる。

$('#doesntexist').slideUp()
// genFx(), speed(), animate()といったメソッドが実行されるが、要素は存在しないため画面上では何の動きもあらわれない

便利なメソッド

eq(), first(), last()

var lastelem = $elems.eq(-1); // get()と同じ

$('#nav li:first') === $('#nav li').first();
$('#nav li:last') === $('#nav li').last();

data()

// 普通の書き方
$(elem).data(key, value);

// 10倍速い!
$.data(elem, key, value);
305
308
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
305
308