jQueryの汚染をなくした上で、$を使ったパフォーマンスベンチマーク
jQueryの話を社内ブログの方に書いたのだけど、よくよく考えてみたら僕が外から見れないなと。
ってことでこっちにも同じ内容。
# 自分がばれそうなところは変更。
# って言っても社内の人にはばれるのか。
jQueryを使いながらJavaScriptを書いているのだけど、
ユーザ向けに、なるべくグローバル変数を汚さないようにしようと、
jQueryで使われるグローバル変数「jQuery」と、そのショートカットの「$」を
「A.B.dom」にしようとした。
こうすればユーザの「$」は生きるし、Aのみグローバル変数を汚すだけなので。
で、ある程度までできあがったものの、「$」で済むところが、
「A.B.dom」になってるから正直見にくい。
ということでやり直し。
クロージャを使ってA.B.domを$に代入して全体を書いてみようかなと。
# まぁ、あんまりクロージャわかってないから嘘言ってるかもしれないけど。
で、関数を超えて変数を参照するから重くなるかな?と思い、
一応ベンチマーク。
# ベンチマークの関数は404 Blog Not Found:javascript vs perl - プライベート変数による初期化のを使わせていただきました。
で、実験。
やりたいことは、
1.グローバルは「A」って変数しか汚さない
2.今まで「A.B.dom」だった部分を「$」に変更して実行できるか。
ってところだけなので、下のような関数書いてみた。
これが上手く動けば2.の確認OK。
/* * $ を使い回す */ (function(){ window.A = {}; window.A.B = {}; window.A.B.dom = jQuery.noConflict(true); // 汚染回避 var $ = window.A.B.dom; $.fn.extend({ a : function (id) { for (var i=0; i<1000; i++) { // 1000回 $ を参照 if ($) continue; } return $(id).html('jquery'); } }); })() /* * A.B.dom を使い回す */ A.B.dom.fn.extend({ b : function (id) { for (var i=0; i<1000; i++) { // 1000回 A.B.dom を参照 if (A.B.dom) continue; } return A.B.dom(id).html('jquery'); } });
で、jQueryを呼び出す前に以下の2つを宣言しておいて、
最後にこの2つがちゃんと呼び出せれば1.の確認はOK。
window.jQuery = {p: 'jQueryプロパティ'}; // 仮想jQuery window.$ = {p: '$プロパティ'}; // 仮想$
結果。
上が関数aの実行時間で、下が関数bの実行時間。
案外$にした方が速かったという結果になってしまった。
ドット演算ってそんなに遅いのね。今まで書いてたやつ修正しないとかな。
ってか、やっぱりFirefox3Beta5とSafari3.1は速ぇなー。
ソースは下の方に。
- IE6 standalone
- 250ミリ秒
- 719ミリ秒
- IE7
- 250ミリ秒
- 891ミリ秒
- IE8
- 297ミリ秒
- 1094ミリ秒
- lolifox 0.3.2
- 313ミリ秒
- 594ミリ秒
- Firefox 3Beta5
- 73ミリ秒
- 85ミリ秒
- Opera 9.24
- 94ミリ秒
- 141ミリ秒
- Safari 3.1
- 63ミリ秒
- 125ミリ秒
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> window.jQuery = {p: 'jQueryプロパティ'}; // 仮想jQuery window.$ = {p: '$プロパティ'}; // 仮想$ </script> <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script> <script type="text/javascript"> // ベンチマーク関数 // from http://blog.livedoor.jp/dankogai/archives/50968466.html function benchthis(count, func){ var args = []; for (var i = 2, l = arguments.length; i < l; i++) args[args.length] = arguments[i]; var timer = (new Date()).getTime(); for (var i = 0; i < count; i++) func.apply(this, args); return (new Date()).getTime() - timer; } // 出力 function p(output) { document.getElementById('result').innerHTML += output + 'ミリ秒<br />'; } /* * $ を使い回す */ (function(){ window.A = {}; window.A.B = {}; window.A.B.dom = jQuery.noConflict(true); // 汚染回避 var $ = window.A.B.dom; $.fn.extend({ a : function (id) { for (var i=0; i<1000; i++) { // 1000回 $ を参照 if ($) continue; } return $(id).html('jquery'); } }); })() /* * A.B.dom を使い回す */ A.B.dom.fn.extend({ b : function (id) { for (var i=0; i<1000; i++) { // 1000回 A.B.dom を参照 if (A.B.dom) continue; } return A.B.dom(id).html('jquery'); } }); </script> </head> <body> <div id="test1"></div> <div id="test2"></div> <hr /> <div id="result"></div> <script type="text/javascript"> p(benchthis(100, A.B.dom().a, '#test1')); p(benchthis(100, A.B.dom().b, '#test2')); document.getElementById('test1').innerHTML = jQuery.p; document.getElementById('test2').innerHTML = $.p; </script> </body> </html>