JavaScriptコードを最適化する方法

6455 ワード

JavaScriptコードを最適化する作者:Gregory Baker、GMailソフトウェアエンジニアとEric Avidsson、Google Chromeソフトウェアエンジニアが必要とする経験:JavaScript関連業務知識クライアントスクリプトは、あなたのアプリケーションをよりダイナミックかつアクティブにすることができますが、ブラウザのコードの解析は、効率的な問題を引き起こす可能性があります.このような性能の違いはクライアント間でも異なります.ここではJavaScriptコードを最適化するためのヒントと最適な実践を提供します.文字列を使った接続操作はInterExnet plorer 6と7のゴミ収集に大きな影響を与えます.この問題はInternet Explorer 8の中で解決されますが、文字列はIE 8とその接続になります.これはIEブラウザ(Chromeなど)ではないので、もう少し効率的です.ユーザーの中にインターネットExplorer 6または7を使っている場合が多いです.文字列を構築する方法に十分注意してください.以下のようなコードがあります.
 
  
var veryLongMessage =
'This is a long string that due to our strict line length limit of' +
maxCharsPerLine +
' characters per line must be wrapped. ' +
percentWhoDislike +
'% of engineers dislike this rule. The line length limit is for ' +
' style purposes, but we don't want it to have a performance impact.' +
' So the question is how should we do the wrapping?';
接続するよりジョン():
 
  
var veryLongMessage =
['This is a long string that due to our strict line length limit of',
maxCharsPerLine,
' characters per line must be wrapped. ',
percentWhoDislike,
'% of engineers dislike this rule. The line length limit is for ',
' style purposes, but we don't want it to have a performance impact.',
' So the question is how should we do the wrapping?'
].join();
同様に、条件文とサイクルの間に接続して文字列を構築するのは非効率的です.エラーの方式:
 
  
var fibonacciStr = ' 20 ';
for (var i = 0; i < 20; i++) {
fibonacciStr += i + ' = ' + fibonacci(i) + '
';
}
正しい方法:
 
  
var strBuilder = [' 20 :'];
for (var i = 0; i < 20; i++) {
strBuilder.push(i, ' = ', fibonacci(i));
}
var fibonacciStr = strBuilder.join('');
補助関数で生成された文字列を構築します.
短い結果を格納する文字列を避けるために、伝達文字列ビルダ(配列または補助クラス)を関数に構築します.
例えば、BildMenuItemHtml_を仮定する.文字列と変数で文字列を構築し、文字列ビルダーを内部で使用します.
 
  
var strBuilder = [];
for (var i = 0; i < menuItems.length; i++) {
strBuilder.push(this.buildMenuItemHtml_(menuItems[i]));
}
var menuHtml = strBuilder.join();
使用しない:
 
  
var strBuilder = [];
for (var i = 0; i < menuItems.length; i++) {
this.buildMenuItem_(menuItems[i], strBuilder);
}
var menuHtml = strBuilder.join();
クラスを定義する方法
以下のコード効率は高くないです.baz.Barのインスタンスを構築するたびに、fooのために新しい関数とクローズドを作成します.
 
  
baz.Bar = function() {
//
this.foo = function() {
//
};
}
おすすめの方法は:
 
  
baz.Bar = function() {
//
};
baz.Bar.prototype.foo = function() {
//
};
このようにして、いくつかのbaz.Barのインスタンスを構築しても、一つの関数を作成してfooに与えます.
初期化インスタンス変数
値タイプ(非参照)の初期化値(例えば、タイプは数字、ブール値、null、undefinedまたは文字列の値)を持つ変数宣言/初期化コードを直接prototypeプロトタイプに入れます.これは、コンストラクションを呼び出すたびに初期化コードを実行する必要がないことを避けることができます.(この方法は、コンストラクタパラメータによって初期化値が決定されたり、構成されたりするときの状態が不確定なインスタンス変数に適用できません.)
例えば、書くより:
 
  
foo.Bar = function() {
this.prop1_ = 4;
this.prop2_ = true;
this.prop3_ = [];
this.prop4_ = 'blah';
};
むしろ、
 
  
foo.Bar = function() {
this.prop3_ = [];
};
foo.Bar.prototype.prop1_ = 4;
foo.Bar.prototype.prop2_ = true;
foo.Bar.prototype.prop4_ = 'blah';
クローズドを慎重に使う
クローズドはJavaScriptの中の一つの強大で有用な特性です.しかし、それらも悪いところがあります.
これらは最も一般的なメモリリーク源です.
閉じられたパケットを作成するのは、閉じられていないインライン関数を作成するよりも明らかに遅く、静的関数を再利用するよりも遅くなります.
 
  
function setupAlertTimeout() {
var msg = ' ';
window.setTimeout(function() { alert(msg); }, 100);
}
下のコードより遅いです.
 
  
function setupAlertTimeout() {
window.setTimeout(function() {
var msg = ' ';
alert(msg);
}, 100);
}
以下のコードより遅いです.
 
  
function alertMsg() {
var msg = ' ';
alert(msg);
}
function setupAlertTimeout() {
window.setTimeout(alertMsg, 100);
}
彼らはスコープの階層を追加しました.ブラウザが属性を解析する時、スコープの階層ごとにチェックしなければなりません.次の例では、
 
  
var a = 'a';
function createFunctionWithClosure() {
var b = 'b';
return function () {
var c = 'c';
a;

c;
};
}
var f = createFunctionWithClosure();
f();
fが呼び出されると、参照aは参照bよりも遅く、それらは参照cよりも遅い.
IE+JScript Performance Recommandations Part 3を参照してください.JavaScript Code inefficienciesは、IEでのクローズド使用に関する情報をより多く取得します.withの使用を避ける
あなたのコードの中でwithを使用しないようにしてください.機能に非常に悪い影響があります.作用領域チェーンを修正して、他の作用領域での変数を検索することが高くなります.
ブラウザのメモリの漏洩を避ける
メモリリークはWebアプリケーションにとって非常に一般的な問題であり、深刻な性能問題をもたらします.ブラウザのメモリ使用が上昇すると、Webアプリケーションは、ユーザーシステムの他の部分と一緒に遅くなります.Webアプリケーションの最も一般的なメモリリークの原因は、JavaScriptスクリプトエンジンとブラウザDOMのC++オブジェクト実装間の循環参照です.(例えば、JavaScriptスクリプトエンジンとInternet ExplorerのCOMインフラストラクチャ間、またはJavaScriptエンジンとFirefoxのXCOMインフラストラクチャ間).
以下はメモリの漏れを避けるためのいくつかの経験則です.
イベントシステムを使用して、イベント処理関数を追加します.
最も一般的な循環参照モード[DOM要素-->イベントハンドラ関数>>クローズドスコープ-->DOM]はこのMSDNのブログ記事で議論されています.この問題を避けるために、Google doctype、Dojo、or JQueryなどの厳格なテストを経たイベントシステムを使用してイベントハンドリング関数を添付します.
また、IEでインラインのイベントハンドリング関数を使用すると、他のタイプのリークが発生します.これは通常の循環参照リークではなく、メモリ内の一時的な匿名シナリオオブジェクトのリークです.詳細は、理解と解決IEリークモード(Undenting and Solving Internet Explorer Leak Patterns)の「DOM挿入順序リークモデル(DOM Insention Order Reder Moder)」を確認してください.一つは、他にもJavaScript Kit教程にもう一つの例があります.
拡張属性の使用を避ける
拡張属性はDOM要素に付加された任意のJavaScript属性であり、循環参照の一般的な原因でもあります.拡張属性を使うとメモリが漏れないようにできますが、誤って漏れを導入しやすくなります.この漏れのパターンは、「DOM元素」拡張属性-->中間オブジェクト-->DOM元素です.最善の方法はそれらの使用を避けることです.それらを使うなら、単純な値タイプだけを使います.単純なタイプではないなら、拡張属性が必要でない時は空にします.IE漏洩モード(Understanding Internet Explorer Leak Patterns)の「循環参照」を参照してください.