jQuery ちょっと高速化に挑戦してみる
jQueryを使っていると「なんだかもっさりするな。。。」と思う場合があります。こういう場合、書き方を見直す事で、かなり改善する場合があります。今回は「ちょっと高速化」を目標に書き方のポイントを紹介してきます。
■ 要素選択の記述を見直す
jQueryはセレクタやトラバースメソッドを使って要素を選択しますが、書き方によって大幅にパフォーマンスが上がる場合があります。
下記HTMLの中の「※ ここを見つける ※」というテキストを「■■■ 書き換えたよ ■■■」に入れ替えたい場合、どう書きますか?
<script> $(function(){ ○○○.text("■■■ 書き換えたよ ■■■"); }); </script> <div id="wrap"> <div id="content"> <h1>タイトル</h1> <p class="text">テキスト..................</p> <div class="text">※ ここを見つける ※</div> <div class="text">テキスト..................</div> </div> </div>
テキストの書き換えは「.text(“■■■ 書き換えたよ ■■■”)」で書き換えることができます。その前の要素を選択するところ(○○○)を考えて見て下さい。
おそらく人によって書き方がかわってくると思います。思いつくものを、ざっと下記に上げてみました。
<script> $(function(){ $("p + div").text("■■■ 書き換えたよ ■■■"); //0.679秒 $("p").next().text("■■■ 書き換えたよ ■■■"); //0.693秒 $("#content").find("div").first().text("■■■ 書き換えたよ ■■■"); //0.746秒 $("#content div").eq(0).text("■■■ 書き換えたよ ■■■"); //0.767秒 $("div.text").first().text("■■■ 書き換えたよ ■■■"); //0.762秒 $("#content div").first().text("■■■ 書き換えたよ ■■■"); //0.778秒 $("p").next("div").text("■■■ 書き換えたよ ■■■"); //0.808秒 $("div#content").find("div").first().text("■■■ 書き換えたよ ■■■"); //0.945秒 $("div.text:contains('※ ここを見つける ※')").text("■■■ 書き換えたよ ■■■"); //1.164秒 $("div.text:first").text("■■■ 書き換えたよ ■■■"); //1.803秒 $(".text").eq(1).text("■■■ 書き換えたよ ■■■"); //0.697秒 $("div.text").eq(0).text("■■■ 書き換えたよ ■■■"); //0.753秒 }); </script>
後ろに添えている「//○○秒」は繰り返し同じ処理をさせたときにかかった時間です(Firefox7で10000回ループでチェック)。上から順番に実行結果の速い順に並べています。一番速いものに比べ、遅いものは3倍近く時間がかかっています。上記の動作確認ページが下記です。
このように要素取得の書き方の違いだけで、これだけの差がでてきます。では具体的に書き方のポイントを見ていきましょう。
まず下記2つ。
$("div.text:first").text("■■■ 書き換えたよ ■■■"); //1.803秒 $("#content div:first").text("■■■ 書き換えたよ ■■■"); //1.815秒
遅い原因は「:first」です。「一番最初のもの」という指定ですが、かなり実行に時間がかかります。これは「.first()」を使うことでかなり速度が上がります。「:○○」系のものは、実行に時間がかかってしまうものがいくつかあるようなので、代用できるメソッドが用意されている場合は、そちらに書き換えましょう。
次に下記を見比べて下さい。
$("#content").find("div").first().text("■■■ 書き換えたよ ■■■"); //0.746秒 $("div#content").find("div").first().text("■■■ 書き換えたよ ■■■"); //0.945秒
違うのはセレクタに「div」を付けているかどうか、というだけです。この記述だけで20%以上速度が変わっています。id属性はページ内に一意(一個だけ)というルールがあるので、HTMLタグを指定する必要はありません。id属性を検索する場合はHTMLタグを付けないようにしましょう。
「 $(id属性) 」は「 $(HTMLタグ) 」と指定するよりも速度が上がります。もしid属性が割り当てる事ができるのであればHTMLタグにidを割り当て利用してみてください。
では次。
$("#content").find("div").first().text("■■■ 書き換えたよ ■■■"); //0.746秒 $("#content div").first().text("■■■ 書き換えたよ ■■■"); //0.778秒
「$(“#content”).find(“div”)」「$(“#content div”)」はともに「id contentの要素の中のdivを選択」という記述ですが、「find()」を利用した方が少し速くなります。書く時には「$(“#content div”)」の方が見やすいので、自分自身こちらを使う事が多いのですが、少しでも速度UPをしたい方は「find()」を使うようにしましょう。
次はclass属性の指定について。
$(".text").eq(1).text("■■■ 書き換えたよ ■■■"); //0.697秒 $("div.text").eq(0).text("■■■ 書き換えたよ ■■■"); //0.753秒
「class属性を指定する場合はHTMLタグも指定する方が速いよ!」と覚えている方もいるかと思いますが、基本IEのバージョン8以下の場合です。もしスマートフォンのみをターゲットにした場合、HTMLの記述(classの指定箇所やHTMLタグの数)次第では、HTMLタグ指定はない方が速度UPすることがあります。
と、ここまでをまとめると、
・「:○○」系のものは、代用できるメソッドや書き方があれば、そちらを利用する。
・ id属性にHTMLタグは付けない。もしHTML側でid属性を付けることができるなら、積極的に利用する。
・ find() メソッドは積極的に利用する。
・ class属性にHTMLタグを添えるとIEのバージョン8以下では速くなる。それ以外ブラウザの場合はHTMLタグがない方が速度UPの可能性あり。
となります。
■ 繰り返す記述を見直す
「繰り返す記述」というのは何回もプログラムを実行する記述箇所です。下記の悪い例、良い例を見比べて下さい。
【悪い例】
$("#content").append("<p>書き換え済み</p>"); $("#content").find(".text").css("color","red"); $("#content").find(".text").text("■■■ 書き換えたよ ■■■");
【良い例】
var content = $("#content"); var content_text = content.find(".text"); content.append("<p>書き換え済み</p>"); content_text.css("color","red").text("■■■ 書き換えたよ ■■■");
悪い例では「 $(“#content”) 」が3回、「 $(“#content”).find(“.text”) 」が2回記述されています。「 $(“….”) 」と記述すると指定された要素を抜き出す処理が実行されます。「 $(“#content”) 」が3回記述されているといことは、同じものを3回抜き出す処理が実行されているということです。
良い例では、抜き出したものを変数に入れ、その後は変数の中身を利用することで、何度も同じ処理を実行しないようにしています。
また良い例の方では「.css(“color”,”red”).text(“….”)」と処理をつなげています。同じ要素に対して複数の処理をしたい場合、「.(ドット)」でつなげて記述することができます(これをメソッドチェーンといいます)。つなげられるものは、つなげて書いてみましょう。
次は、やりがちなfor文の中で何度も処理を実行する例です。
【悪い例】
for(var i=0; i<10; i++){ $("#content").append("<p>テキストを追加しました。</p>"); }
【良い例】
//new Array() = データを入れる配列を生成 var add_data = new Array(); for(var i=0; i<10; i++){ //.push データを配列に入れる add_data.push("<p>テキストを追加しました。</p>"); } //add_data.join('') 配列を結合 $("#content").append(add_data.join(''));
「id content 内に10回コンテンツを追加する」という記述です。
悪い例では「 $(“….”) 」「 append(“….”) 」の2つを10回実行しているので、処理に時間がかかります。これを良い例の方では、それぞれ1回のみ実行するように書き換えています。
良い例のコメントをつけている部分はjQueryではなく、素のJavascriptの記述です。毎回 append でデータを追加するのではなく、追加するデータを一旦配列に入れ、そのデータをまとめて最後に追加しています。
もしfor文やwhile文内で append 等で追加している場合は、良い例のようにforの外で追加するよう書き直してみてください。処理速度は数倍、数十倍UPするはずです。
上記2つの例のように同じ処理を何度もさせるような書き方をしている場合は、できる限り処理が少なくなるような書き方に直しましょう。
■ 最後に処理時間の計り方
実際に書き直しをすると、どのくらい速くなっているか知りたい!と思うはず。たいしたものではないですが、すぐに計測できるようスクリプトを付けておきます。これを利用して今どれくらい時間がかかっているのか、書き直してどのくらい速くなったか確認してみてください。
<script> $(function(){ //繰り返す回数 var end_count = 1000; var start_time = new Date(); for (var start_count=0; start_count<end_count; start_count++){ //実行する処理を書く } var end_time = new Date(); var msec = (end_time - start_time)/1000; alert("結果:"+ msec +"秒かかりました"); }); </script>
ふう。。。長くなりましたが、以上の書き方を見直せば、ちょっとどころではなく、えっ!と驚く程速くなるかもしれません。ぜひぜひ高速化に挑戦してみてください。
※ちなみにjQuery本体はできるだけ新しいものを利用した方が速くなる可能性があります。ですが、プラグインが動作しなくなったり、未知のバグがあったりするので、jQuery本体を差し替える場合は要注意です。しっかり動作確認してから差し替えましょう!