jQuery の ID で対象ノードを取得する処理を高速にしたい

December 11, 2008

てっく煮ブログさんのエントリー
jQuery を高速に使う CSS セレクタの書き方 - てっく煮ブログ
をみてて、jQuery の $(“#xxxx”) を速くしたいと考えていたことを思いだした。それについて書く。

jQuery の $(“#xxxx”) について

セレクタをどう処理しているのか jquery-1.2.6.js で確認してみよう。
まず下記の init が $() に相当する。Handle HTML stringsのところで引数が string だと quickExpr.exec が走る。これは正規表現でのセレクタ解析処理である。
その後、HANDLE: $(“#id”)のところでマッチして取得した ID を使って、var elem = document.getElementById 使い、それを return jQuery(elem) として再び init が呼び出される。

jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
// Make sure that a selection was provided
selector = selector || document;
// Handle $(DOMElement)
if ( selector.nodeType ) {
this[0] = selector;
this.length = 1;
return this;
}
// Handle HTML strings
if ( typeof selector == “string” ) {
// Are we dealing with HTML string or an ID?
var match = quickExpr.exec( selector );
// Verify a match, and that no context was specified for #id
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
if ( match[1] )
selector = jQuery.clean( [ match[1] ], context );
// HANDLE: $(“#id”)
else {
var elem = document.getElementById( match[3] );
// Make sure an element was located
if ( elem ){
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id != match[3] )
return jQuery().find( selector );
// Otherwise, we inject the element directly into the jQuery object
return jQuery( elem );
}
selector = [];
}
// HANDLE: $(expr, [context])
// (which is just equivalent to: $(content).find(expr)
} else
return jQuery( context ).find( selector );
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) )
return jQuery( document )[ jQuery.fn.ready ? “ready” : “load” ]( selector );
return this.setArray(jQuery.makeArray(selector));
},

よって、コストがかかっているのは正規表現の解析部分のようなのでこの部分を飛ばして、いきなり jQuery に DOM ノードを渡してあげると速くなりそうだ。

高速化方法とまとめ

IDによる jQuery オブジェクトの取得を下記のように定義しておくと簡単に速くできそうだ。($$ にしたのは prototype.js が $(“xxx”) で取れたりそれっぽいから)

function $$(id) {
return $(document.getElementById(id));
}

(追記)上記の $$ の定義では、指定した ID が DOM ツリーに存在しないときの処理を考慮していない。

Windows Vista SP1 での計測実験 / 1000回実行の計測三回平均

IE 7.0

Firefox 3.0

Opera 9.6

Safari 3.2

jQuery $(“#id”)

707 ms

301 ms

157 ms

129 ms

document.getElementById(“id”)

201 ms

43 ms

35 ms

21 ms

jQuery $$(“id”)

470 ms

126 ms

53 ms

51 ms

document.getElementById は参考値としてです。いずれもブラウザでも $$ による取得の方が速くなっていることがわかる。ただ、IE では他のブラウザほど速くならなかったのが残念だ。

セレクタで ID を指定して取得を行うことはよくある。アプリの規模によってはこういった高速化を施しておくのも良いだろう。

テスト用のHTML

上記の計測に使った HTML ソースをべた貼りしておく。

jQuery getElementById() の計測テスト

テスト回数 :

テストノード 取得テスト用 dummy

var d = $("#dummy");

var d = document.getElementById("dummy");

function $$(id) {
return $(document.getElementById(id));
}
var d = $$("dummy");

alert($$("dummy").find(".best").text());

jQuery 1.3 において(2009/1/18 追記)

上記を jquery-1.3.min.js に差し替えて計測してみましたが、変わらずでした。

tilfin freelance software engineer