2010年10月31日日曜日

JavaScriptでよくある性能劣化ポイント

WEB+DB PRESS vol.59より。
自分のためのメモ代わりとして、気になった部分をピックアップ。

まずポイント列挙
JavaScriptコード上でよく見られる性能劣化ポイント(抜粋)。
以下、まず列挙します。リンクはページ内アンカです。
  1. 意図しない変数のグローバル化
  2. コストの高い配列アクセス方法を利用
  3. try/catchの間違った使用
  4. ブラウザの再描画について

意図しない変数のグローバル化
JavaScriptでは、関数内で変数を参照する際にまず自身のスコープ内を探します。
見つからない場合、入れ子になっている関数であれば外側の関数のスコープをたどっていき、グローバルスコープは必ず最後に探索されます(スコープチェイン)。そのため、グローバル変数を発見するのは時間がかかることになります。
また、「var」をつけずに宣言された変数はグローバル変数となります。
なので、グローバルにする必要のない変数は必ず「var」を付けて宣言しましょう。
関連:JavaScriptのクロージャ、スコープチェインについての記事(World Wide Windblue)

コストの高い配列アクセス方法を利用
配列にアクセスするには、以下の2通りの方法がある。
  1. メソッド呼び出し
    後発で使用追加されたメソッドを呼び出すこと。(Array.pushなど)
  2. プリミティブ操作
    原始的なアクセス方法

プリミティブ操作を使用するほうがパフォーマンスが高くなる。

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点。
  1. DOMに対する「スタイルの取得」と「スタイルの変更」を混ぜない
  2. DOMに対する「スタイルの変更」は短時間ですばやく行う

0 件のコメント:

コメントを投稿


Related Posts Plugin for WordPress, Blogger...