事の発端。
ってなモチベーションで調べた一連の内容です。
jQueryとSizzleの関係
あらためて一応。
「jQueryといえば」な以下のようなコード。
var $hoge = $('#hoge'); // こういうのとか var $fuga = $('.fuga'); // こういうのとか $hoge.find('.foo'); // こういうのとか $hoge.text(); // 実はこういうのも
そう、いわゆるこのセレクタの実態がSizzleなのです。
正確にはもう少し他のメソッドにも関係があります。
で、そのSizzleがjQueryの中でどういう動きをしてるかを調べてみるエントリでございます。
コードを読む
それが一番はやかろうということで、jQueryの2.xの最新版を読んでいく。
jquery/src/core/init.js
コレがいわゆる本丸、$(selector, context) のところ。
contextはさておき、selectorがどう判別されていって動いてるかをざっくり書くと。
selectorが文字列なら
- '<div>' みたいな文字列なら
div要素を作ってそれをラップした$オブジェクトにしてreturn
- '#hoge' みたいな文字列なら
document.getElementById('hoge')したものをラップした$オブジェクトにしてreturn
- それ以外は$.fn.findしたものをreturn
これが実は重要なので、[*1]で後述。
selectorがDOMElementなら
- その要素をラップした$オブジェクトにしてreturn
そのほかselectorが関数の場合などなど
今回は気にしないので割愛。
[*1] $.fn.find()とは
上述した流れで、$('#id')以外のだいたいのセレクタがココにたどり着くことになるのですが、
これが実はそのまんまSizzleに渡ります。
idが最速
この時点で言えることですね。
そもそもSizzleに渡らないので、以降の処理や判定がない分速いです。
つまり速さを追い求めてるなら、'#hoge'的な文字列を渡す使い方しかしちゃダメってことです!!!1
冒頭に立ち戻る
で、今回はSizzleの有無による差分が気になるエントリなので、2パターンについてそれぞれ追っていきます。
ちなみに、さっきのリポジトリでもその差分はさくっと見れます。
jquery/selector-native.js at 2.1-stable · jquery/jquery
jquery/selector-sizzle.js at 2.1-stable · jquery/jquery
この2つのファイルが差分になってる模様。
Sizzleがない場合、jQueryとしての実装がある感じ。
Sizzleを使ってない場合のfind
94行目あたり。
というわけで、単にqurySelectorAllしたものをラップして返すようになってます。
なので、querySelectorAllが存在してて、ちゃんと動く前提であることがわかります。
このファイルの冒頭のコードコメントにも、外すなら自己責任でやれよって書いてあります。
そして、このコードのI/Oを保てば、独自のSizzleみたいなのも作れるよとも。
Sizzleを外すメリット
というわけで、です。
そういう条件下なら、初期化コストとファイル容量がちょっと下がるのでパフォーマンスは良くなる。
まぁならなんでjQuery使ってるのっていう話になるパターンばっかな気はするけど。
まあjQueryだけ読み込んで何もしないページのパフォーマンス測っても、
10msくらいしか早くならなかったので、そうそう選ばない選択肢かなー。(@PC/ChromeCanary)
Sizzleを外すデメリット
- querySelectorAllが遅い環境の場合、余計に遅くなる可能性がある
- querySelectorAllのバグfixやpolyfillがない
- その他Sizzleのブリッジ関数たちも同じく
- やんちゃなセレクタが使えない
querySelectorAll
モバイルではすっごい遅かったイメージがあって、暗黙の内に使ってなかったんですけど、
やっぱりまだちょっと遅いですね・・。
実機で見たら案の定だった
iPhone4/iOS7 と iPhone6/xiOS7、querySelectorAllのパフォーマンス8-20倍くらい違うんですけどこれは
— りぃ (@leader22) January 8, 2015
ちなみにgetElementByIdだともっと差が開く(120倍とか・・
— りぃ (@leader22) January 8, 2015
GaralxyS3/Android4.0のqSA、iPhone4/iOS7と同じかそれ以下という事実
— りぃ (@leader22) January 8, 2015
Backbone.Marionette使ってるなら
Marionette使ってる場合にViewでよく使うuiってありますよね。
あのMarionette.Viewは、uiオブジェクトを作る時に全部findで探しに行く実装になってるので、
せっかくのidも、もれなく全部querySelectorAllされるハメになります。
どういう意味かわかりますよね・・。