uupaa.js version 0.6 をリリースしました。
変更点: http://uupaa-js.googlecode.com/svn/trunk/CHANGELOG.htm
注意点
version 0.6 では CSSセレクタ(uu.css)を書き直しています。
→ querySelectorAll相当の機能を実装してみた(uupaa.jsのCSSセレクタを書き直した) - latest log
jQueryと比較した場合に、CSSセレクタとしての精度はuupaa.jsが上なのですが、速度的にはjQueryに100倍ぐらい差をつけられている項目がありました。
『まず正しく動くものを書き、その後に早くする』という格言
遅い部分については次以降のバージョンで改善していきますが、それでもトータルの速度ではjQueryに勝てない気がします。
なぜなら、jQueryは本来必要なチェックをすっ飛ばして速度を稼いでいる箇所が沢山あるからです。
ハンデ戦でしたが、無事勝ちました
と、頭で分かっていても、
「苦労して高精度のCSSセレクタが出来た。でも(見た目の)速度で負けちゃった」では、なんか悔しいのです。
なので、ここから下は悔しさを晴らすために色々と書きます。
現実世界ではIDセレクタとCLASSセレクタがあれば、だいたいOK
分業制でWebサイトを構築する場合に、多用するセレクタといえばIDセレクタとCLASSセレクタです。
背景には、「IE6のCSSセレクタが貧弱なため、IDとCLASSだけを頼りに設計せざるを得ない」という現実があります。
jQueryの良いところ
jQueryは一つの万能セレクタが全ての出発点となる設計です。
C++などのオブジェクト指向言語において、jQueryのような特徴を持つ(メソッドチェーンや万能性を謳う)ライブラリというのは過去にもありました、が…
そのようなライブラリは、
- より高速なライブラリが登場したときに、速度を稼ぐ手段がなく埋もれていく。
- メモリを大食いする。必要の無いスタックを必ず浪費する。関数ネストが深すぎる。→ デバッグしづらい
- バージョンアップするごとにI/Fが醜くなっていく。機能毎にドメイン(名前空間)が切れないため、グローバル関数の塊に近い状態になってしまう。
- 演算子のオーバーロードやら、コンストラクタが10個もあったりしてキモイ
という欠点が目立ち、次第に消えていきました。
jQueryは現時点でこれらのデメリットともうまくバランスを取っているため、それで人気が高いのでしょう。
uupaa.js は、歴史を繰り返さないために、シチュエーションにあわせた専用のセレクタやメソッドをわざわざ用意しています。
どーん。
以下の表を見て下さい。
uupaa.jsとjQueryが提供している機能の中から最適な方法を選び、1000個のdiv要素を検索する時間を測定したものです。
ループコストや関数呼び出しコストは可能な限り数値に含まれないように(なんやかんや)してます。
また、統計的なブレは除去済みです。単位はmsです。
<div id="root"> <div class="aaa bbb ccc ddd" id="id0">id0</div> <div class="aaa bbb ccc ddd" id="id1">id1</div> : : <div class="aaa bbb ccc ddd" id="id9999">id9999</div> </div>
"id0" から "id999" までのidを持つ要素を検索する(API = getElementById)
Browser | API | v0.6:uu.id("...") | jQuery("#...") | コスト差 |
---|---|---|---|---|
IE6 | 956.3 | 7.7 | 1040.7 | 135倍 |
IE8β2 | 106.0 | 4.6 | 174.9 | 38倍 |
Firefox2 | 15.7 | 4.6 | 63.9 | 14倍 |
Firefox3 | 4.0 | 1.1 | 25.1 | 23倍 |
Opera9.27 | 9.2 | 1.5 | 31.2 | 21倍 |
Opera9.6β | 3.1 | 0.0 | 15.7 | 15.7倍以上 |
Safari3.1 | 0.0 | 0.0 | 15.5 | 15.5倍以上 |
Chrome | 3.0 | 1.0 | 14.0 | 14倍 |
div要素を検索する(API = getElementsByTagName)
Browser | API | v0.6:uu.tag("div") | v0.7:uu.tag("div") | jQuery("div") | コスト差 |
---|---|---|---|---|---|
IE6 | 0.0 | 15.7 | 12.4 | 15.7 | 1.3倍 |
IE8β2 | 0.0 | 9.3 | 4.6 | 10.8 | 2.4倍 |
Firefox2 | 0.0 | 1.5 | 1.5 | 6.1 | 4倍 |
Firefox3 | 0.0 | 1.4 | 1.4 | 3.0 | 2倍 |
Opera9.27 | 0.0 | 0.0 | 0.0 | 7.7 | 7.7倍以上 |
Opera9.6β | 0.0 | 0.0 | 0.0 | 0.0 | 不明 |
Safari3.1 | 0.0 | 0.0 | 0.0 | 0.0 | 不明 |
Chrome | 0.0 | 0.8 | 0.8 | 1.0 | 1.2倍 |
追記: uupaa.js ver0.7 で uu.tag が若干早くなりました。
classに"ddd"を含む要素を検索する(API = getElementsByClassName)
Browser | API | v0.6:uu.klass("ddd") | v0.7:uu.klass("ddd") | jQuery(".ddd") | コスト差 |
---|---|---|---|---|---|
IE6 | --- | 46.9 | 29.5 | 36.0 | 1.2倍 |
IE8β2 | --- | 23.4 | 15.6 | 18.9 | 1.2倍 |
Firefox2 | --- | 23.5 | 17.2 | 25.0 | 1.5倍 |
Firefox3 | 0.0 | 2.9 | 2.9 | 7.0 | 2.4倍 |
Opera9.27 | --- | 10.9 | 6.1 | 15.6 | 2.6倍 |
Opera9.6β | 0.0 | 0.0 | 0.0 | 6.1 | 6.1倍以上 |
Safari3.1 | 0.0 | 0.0 | 0.0 | 4.6 | 4.6倍以上 |
Chrome | 0.0 | 0.8 | 0.8 | 3.9 | 5倍 |
追記: uupaa.js ver0.7 で uu.klass が若干早くなりました。
classに"aaa"と"ccc"を含む要素を検索する(API = getElementsByClassName)
Browser | API | v0.6:uu.klass("aaa ccc") | v0.7:uu.klass("aaa ccc") | jQuery(".aaa .ccc") | コスト差 |
---|---|---|---|---|---|
IE6 | --- | 46.8 | 31.1 | 60.9 | 2倍 |
IE8β2 | --- | 31.4 | 15.7 | 31.1 | 2倍 |
Firefox2 | --- | 35.8 | 18.8 | 40.6 | 2.2倍 |
Firefox3 | 0.0 | 2.9 | 2.9 | 10.7 | 3.7倍 |
Opera9.27 | --- | 15.7 | 9.3 | 17.3 | 1.9倍 |
Opera9.6β | 0.0 | 0.0 | 0.0 | 10.8 | 10.8倍以上 |
Safari3.1 | 0.0 | 0.0 | 0.0 | 9.3 | 9.3倍以上 |
Chrome | 0.0 | 0.8 | 0.8 | 5.9 | 7倍 |
追記: uupaa.js ver0.7 で uu.klass が若干早くなりました。
まとめ
最も多用するIDの検索においては100倍以上もの差が見られます。
# jQueryユーザからの反論があれば、計測に使用したHTMLを提供しますよ。
あ、私はjQuery嫌いじゃないですよ、昔書いたライブラリのコンセプトに良く似てて。
でも、このように他のライブラリとの(無視できないほどの)性能上の違いが露呈すると、
ユーザ: jQueryにもさ、ID専用セレクタやCLASS専用セレクタを追加すればいいじゃん。やっちゃってよ。 作 者: 追加は簡単だけど、名前どうしよう、万能セレクタとの住み分けはどうしよう? ユーザ: いいからさ、ごちゃごちゃ言わずに、 $.id() とか $.klass() とかいうのを追加してよ。 作 者: そういうのをどんどんやっちゃうと、jQueryじゃ無くなってしまいそうだよ。
メソッドチェーンにこだわりすぎると、こういったツケを支払う必要が出てきます。
あっそうそう。
カンの良い人は分かると思いますが後でネタばらしします。
「統計」とか「ランキング」ってバスワードなんだよね。