前回確認した contextについて、以下の参考記事を元にbenchmarkを取ってみました。
今回はcode readingなしです(全然進みません)。
参考記事
Brandon Aaron「誤解されてるjQueryの"Context"」 - 以下斜め読んだ内容
こちらの記事が詳しく、興味深いです。
benchmarkの取り方
以下の簡易的に計測するメソッドを用いてブラウザのconsole上で計測しています。
(もっといい方法があれば教えて下さい。)
対象ブラウザは、chrome(45.0.2454.85 (64-bit))、Firefox(40.0.3)です。
IEとかAndroidとかで計測すると、いろいろ違ってくるのかもしれませんが面倒なので実施して無いです。
対象サイトは、http://api.jquery.com/ で、
id=post-45 要素の配下にある header タグを取得するというセレクタのパターンを4種類用意して実施してみました。
function benchmark(callback, loopCount) { loopCount = (loopCount === undefined) ? 100000 : loopCount; var benchmarkKey = 'benchmark ' + loopCount; console.time(benchmarkKey); for (var i = 0; i < loopCount; i++) { callback(); } console.timeEnd(benchmarkKey); }
本題
1. contextの指定
//誤解してる人の意図に反してcontextはdocument要素のまま $('a', '#myContainer').context; //ちなみに上は内部的には下のように変換 $('#myContainer').find('a');
なるほど、まずは以下の4つでcontextを確認してみます。
No. | Pattern | Result |
---|---|---|
1 | $('#post-45').find('header').context; | document |
2 | $('header', $('#post-45')[0]).context; | #post-45 (意図したcontext) |
3 | $('#post-45 header').context; | document |
4 | $('header', '#post-45').context; | document |
NO.2 のみ意図した結果となりました。
2. 高速なのは?
//DOM指定の高速な順番はこれ $('#myContainer').find('a'); //1 $('a', $('#myContainer')[0]);//2 find()使うよりわずかに遅い $('#myContainer a');//3
「1」と同様のパターンで計測してみます。
No. | Pattern | Result(Chrome) | Result(Firefox) |
---|---|---|---|
1 | benchmark(function() { $('#post-45').find('header'); }) | 244.543ms | 293.31ms |
2 | benchmark(function() { $('header', $('#post-45')[0]); }) | 303.033ms | 402.35ms |
3 | benchmark(function() { $('#post-45 header'); }) | 259.614ms | 11659.9ms |
4 | benchmark(function() { $('header', '#post-45'); }) | 259.173ms | 385.02ms |
以下わかったこと
1) No.4 のように間違ったcontextでもそこそこ速いです。
No.2とNo.4の差は、誤差程度です。
つまり、間違ってcontextを指定しても、そこそこ軽快に動作してくれています。
jQueryが以下のように実行してくれているので、そんなに悲観することはなさそうです。
// 1. (constructor はjQuery) this.constructor( context ).find( selector ); // 2. ( context || rootjQuery ).find( selector );
2) No.3 は実行環境によっては遅いです。
Chromeだと結構早く動作するのですが、Firefoxだと超絶遅いです。
遅くなる理由も参考記事に詳しく書かれています。
Sizzleはセレクタの「右側」からノードの指定を行っていく Sizzleの動作はブラウザのCSSセレクタの解釈と同じ
でも、Chromeは非常に高速です。どういうことなんでしょうか。
ChromeだとNo.1〜4はほぼ差がありません。
3. .on() では?
気になるのが、参考記事では .live() について言及されています。
.on()(.live()) はまだソースみていないのですが、気になったのでこちらも計測してみました。
No. | Pattern | Result(Chrome) | Result(Firefox) |
---|---|---|---|
1 | benchmark(function() { $('#post-45').find('header').on('click', {} ); }) | 827.703ms | 814.73ms |
2 | benchmark(function() { $('header', $('#post-45')[0]).on('click', {} ); }) | 888.886ms | 935.77ms |
3 | benchmark(function() { $('#post-45 header').on('click', {} ); }) | 1047.385ms | 13138.24ms |
4 | benchmark(function() { $('header', '#post-45').on('click', {} ); }) | 942.957ms | 1219.65ms |
どうやら、No.4 の指定方法だと若干遅くなっているようですが、さほど(No.3ほどではない)影響は無いようです。
結論
No.3 の$('#post-45 header') のセレクタを連結する方法は、DOMの状況や環境によっては問題が出てくる可能性あり。
速度を気にするなら、No.1 のfind を使う。
どうやら、No.4 の間違ったcontext指定でもあまり影響はなさそうですが、
(積極的ににこれで良いとは言い切れないので)極力正しい方法で指定したほうが多分良いかと思います。