jQueryは非常に強力なライブラリですが、使い方を間違えると処理が重くなりがちです。
今回は簡単な方法で高速化が期待できる、jQueryの書き方のポイントをご紹介したいと思います。
1. 速いセレクタを使う
jQueryは $('#id')
のように、CSSセレクタを記述する事でDOM要素を取得することができます。
このjQueryセレクタは非常に強力な機能ですが、記述方法によってはパフォーマンスを低下させてしまう可能性があります。
最も速いセレクタは idセレクタ です。
これはjQuery内部で getElementById()
を使用しているためです。
ただし、下のようにタグセレクタにidセレクタを付けてしまうと、速度が落ちてしまいます。
1 2 |
$('#id'); // => idはページに一つなので高速 $('p#id'); // => ページ内のp要素全てから探すので低速 |
次に高速なのは タグセレクタ です。
1 |
$('p'); |
これもidセレクタと同じく、 getElementsByTagName()
を使用しているためです。
classセレクタ は、 getElementsByClassName()
を使用できるモダンブラウザではやや高速ですが、InternetExplorer8とそれ以前のバージョンでは、処理が Sizzle に引き継がれるため速度が低下します。
1 |
$('.class'); |
また、ネストした要素を指定する場合、セレクタにまとめて記述するよりも、idセレクタで指定した要素から find()
で指定する方が高速です。
1 2 |
$('#id .class'); // => 先に.classを探すので低速 $('#id').find('.class'); // => .classの検索範囲を絞れるので高速 |
もしくは、子孫要素全てから検索する .find()
と違い、直接の子要素のみから検索する .children()
メソッドや、CSSの子セレクタを使う $('#id > .class')
のような指定の仕方もありますが、実際にこれらを計測してみたところ下のような結果が得られました。
(それぞれ20回試行の平均値)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// テストコード $(function() { var $list = $('#list'); for (i=0; i<1000; i++) { list.append('<li>' + i + '</li>'); } console.time('timer'); for (i=0; i<1000; i++) { var $item = $('#item' + i).find('.text'); } console.timeEnd('timer'); }); |
- $(‘#id .class’) -> 164.6142ms
- $(‘#id > .class’) -> 110.6903ms
- $(‘#id’).find(‘.class’) -> 7.22545ms
- $(‘#id’).children(‘.class’) -> 9.88115ms
CSSセレクタを使用した場合と、 .find()
や .children()
を使用した場合では、大きな差が出ていることがわかります。
また、.find()
と .children()
では、僅かに .find()
の方が高速でした。
2. jQueryオブジェクトをキャッシュする
$('.class')
とすると、jQueryはDOM要素を探してきて jQueryオブジェクト を生成して返します。
同じ要素を複数回操作する場合、jQueryオブジェクトをキャッシュしておく事でこの処理を2回目以降省略し、パフォーマンスを改善することができます。
1 2 3 4 5 6 7 8 9 10 |
$('.class').addClass('stay'); $('.class').css('color', 'red'); $('.class').css('fontWeight', 'bold'); // => 遅いクラスセレクタが何度も呼び出されている var $class = $('.class'); $class.addClass('stay'); $class.css('color', 'red'); $class.css('fontWeight', 'bold'); // => $('.class')のjQueryオブジェクトを変数$classにキャッシュする |
また、変数化する事で可読性も上がるので、この手法は積極的に使っていくべきでしょう。
3. メソッドチェーンを活用する
jQueryのメソッドは、その多くがjQueryオブジェクトを受け取ってjQueryオブジェクトを返すよう設計されています。
そのため、一つの処理の後にまた別の処理をつなげて書く事が出来ます。( メソッドチェーン )
メソッドチェーンを利用する事で、同じjQueryオブジェクトを何度も参照し直すことなく、複雑な処理を実装する事が来ます。
1 2 3 4 5 6 7 |
$('.class').addClass('stay'); $('.class').css('color', 'red'); $('.class').css('fontWeight', 'bold'); // => 同じ要素を何度も指定し直している。 $('.class').addClass('stay').css('color', 'red').css('fontWeight', 'bold'); // => jQueryオブジェクトは、メソッドを続けて書く事で受け渡す事ができる |
また、 .css()
などのメソッドは、引数を連想配列で指定する事で、まとめて記述する事も出来ます。
1 2 3 4 |
$('.class').css({ 'color': 'red', 'fontWeight': 'bold', }); |
これらの手法は単純に記述量が減るので、ファイルサイズを抑える事にも繋がります。
4. 1.x系と2.x系を使い分ける
jQueryは現在、IE6〜IE8もサポートしている 1.x系 と、IE9以降を対象とした 2.x系 のふたつが並行して開発が進められています。
それぞれの最新バージョンのファイルサイズは下の通りです。
- jquery-1.11.2.min.js -> 95.931KB
- jquery-2.1.3.min.js -> 84.320KB
1.x系のjQueryには、IE6〜IE8に対応させるため、細かなハックが仕込まれています。
2.x系ではこうした処理が取り除かれているため、より軽量で、より高速で、より安定しています。
ただし1.x系のjQueryにも、モダンブラウザを判別してより高速な処理に分岐させる仕組みが入っています。
(例として、クラスセレクタを使用した場合、モダンブラウザでは getElementsByClassName()
が実行されます。)
そのため、 1.x系と2.x系のjQueryを使い分けたとしても、劇的なパフォーマンス向上が見込めない場合も多くあります。
例えば、スマートフォンサイトでは2.x系、PCサイトでは1.x系というような使い分けが、バランスがいいのではないでしょうか。
5. 別のライブラリを組み合わせる
jQueryは多機能ですが、場合によっては別のライブラリに任せた方がいい場合もあります。
例えば .animate()
は非常に便利ですが、パフォーマンスを悪化させる関数としてよく知られています。
GreenSockのTweenMaxは .animate()
よりも高機能かつ、高速なライブラリです。
下のページでは各ライブラリのスピードテストが行えますが、jQueryとTweenMaxでは大きな差が出ることがわかります。
HTML5 Animation Speed Test
記述の方法もシンプルで、要素の指定にはjQueryが使用できます。
1 2 3 4 5 |
// jQuery $('#id').animate({'left': 1000}, 1000); // TweenMax TweenMax.to($('#id'), 1, {left:'1000px'}); |
もちろん、使用するライブラリが増えれば、それだけ読み込みに時間がかかることにもなります。
パフォーマンスの向上には、それぞれの手法のメリット/デメリットを理解し、状況に応じて使い分ける柔軟性が重要です。