自分のためのメモ代わりとして、気になった部分をピックアップ。
まずポイント列挙
JavaScriptコード上でよく見られる性能劣化ポイント(抜粋)。以下、まず列挙します。リンクはページ内アンカです。
意図しない変数のグローバル化
JavaScriptでは、関数内で変数を参照する際にまず自身のスコープ内を探します。見つからない場合、入れ子になっている関数であれば外側の関数のスコープをたどっていき、グローバルスコープは必ず最後に探索されます(スコープチェイン)。そのため、グローバル変数を発見するのは時間がかかることになります。
また、「var」をつけずに宣言された変数はグローバル変数となります。
なので、グローバルにする必要のない変数は必ず「var」を付けて宣言しましょう。
関連:JavaScriptのクロージャ、スコープチェインについての記事(World Wide Windblue)
コストの高い配列アクセス方法を利用
配列にアクセスするには、以下の2通りの方法がある。- メソッド呼び出し
後発で使用追加されたメソッドを呼び出すこと。(Array.pushなど) - プリミティブ操作
原始的なアクセス方法
プリミティブ操作を使用するほうがパフォーマンスが高くなる。
try/catchの間違った使用
catch節が実行されるたびに新しいスコープが生成・破棄されるため、頻繁に実行されるとパフォーマンスが低下する可能性があります。入力チェック時などエラー判定をするときなどでも、別の方法があるならtry/catch節を排除することが望ましいケースが多いでしょう。
2010 11/1 追記ここから
実際に試してみる。
エラー判定にtry/catchを使わない場合と使った場合で比較。
比較したブラウザはIE7、Firefox3.6.8、Google Chrome7、Opera10.63。
各検証を10回して平均を取った。
エラー判定にtry/catchを使わない場合。
window.onload = function(){
var start = new Date();
for(var i = 0;i < 10000; i++){
var a = 100;
if(typeof a === 'string'){
return a.substring(0, 2);
}else{
}
}
var end = new Date();
alert((end - start));
}
1回の実行にかかった平均の時間。
IE…11(ms)
Firefox…0.6
Google Chrome…0
Opera…1.9
エラー判定にtry/catchを使わない場合。
window.onload = function(){
var start = new Date();
var a = 100;
for(var i = 0;i < 10000; i++){
try{
a.substring(0, 2);
}catch(e){
}
}
var end = new Date();
alert((end - start));
}
1回の実行にかかった平均の時間。
IE…540.7(ms)
Firefox…760.7
Google Chrome…1395
Opera…28.9
(Operaが早すぎて不安です。PCのスペックが低いのも関係あるかもしれません)
2010 11/1 追記ここまで
また、catch節の実行時に生成されるスコープは、ローカルスコープよりも上位に位置します。
そのため、catch節の中で変数を定義することは、それだけで処理のオーバーヘッドになります。
ダメな例。
try{
...
}catch(error){
if(error.code === '500'){
var c = error.code;
...
}
}
この倍、errorオブジェクトに対する処理は別の関数に委譲するコトでパフォーマンスへの影響を最小限に抑えられる。
関数かされた処理はcatchスコープから呼び出されても、ローカル変数は通常のローカル変数スコープ内に定義されます。
よい例。
try{
...
}catch(error){
handleError(error);
}
ブラウザの再描画について
JavaScriptによりDOM要素の位置やサイズ変更、新たなDOM要素の追加などを行うと、ブラウザはその変更を表示されているWebページに反映しなくてはなりません。このような場合にブラウザの再描画が発生しますが、再描画に要するコストは高く、頻繁に発生すると深刻なパフォーマンス低下を招きます。
再描画の回数を減らすポイントは次の2点。
- DOMに対する「スタイルの取得」と「スタイルの変更」を混ぜない
- DOMに対する「スタイルの変更」は短時間ですばやく行う