2012-03-06 14 views
21

私はJavaScriptコードをいくつか書いていますが、長さメソッドが "事前計算"されているのか、JSエンジンによって記憶されているのか不思議でした。私は、配列の長さのために、本当に頻繁にチェックして、私は(閉鎖を通じて、それは不変にする)、それを変更していないよと仮定していた場合は、Javascript:lengthメソッドは効率的ですか?

私はlengthメソッドを事前に計算する必要があります

ので、質問がありますいくつかの変数に格納しますか?

ありがとうございます!

+2

そこには 'length' **方法は、組み込みのJavaScriptのオブジェクトに**ませんが、オブジェクトのプロパティにアクセスすると、多くの場合、ローカル変数にアクセスするよりも遅くなります。 – kirilloid

+0

あなたのページがうまく動作せず、許容範囲内で実行できない場合は、配列インスタンスの ".length"への参照がいくつかあります。 – Pointy

+3

なぜ@Pointlyですか?コード内のすべての改善を探すことはできませんか?私はちょうど興味がありませんか? – santiagobasulto

答えて

6

すべての主要なインタプリタは、ネイティブ配列の長さに対して効率的なアクセサを提供しますが、NodeListのような配列のようなオブジェクトでは効率的ではありません。

"Efficient looping in Javascript"

Test/Browser    Firefox 2.0 Opera 9.1 Internet Explorer 6 
Native For-Loop    155 (ms) 121 (ms) 160 (ms) 
... 
Improved Native While-Loop 120 (ms) 100 (ms) 110 (ms) 

"Efficient JavaScript code"これらのいずれもが電子である

for(var i = 0; i < document.getElementsByTagName('tr').length; i++) { 
    document.getElementsByTagName('tr')[i].className = 'newclass'; 
    document.getElementsByTagName('tr')[i].style.color = 'red'; 
    ... 
} 

var rows = document.getElementsByTagName('tr'); 
for(var i = 0; i < rows.length; i++) { 
    rows[i].className = 'newclass'; 
    rows[i].style.color = 'red'; 
    ... 
} 

を示唆しています効率。 getElementsByTagNameは、静的配列ではなく動的オブジェクトを返します。ループの状態がチェックされるたびに、Operaはlengthプロパティを調べるためにオブジェクトを再評価し、それが参照する要素数を計算しなければなりません。これは、静的な番号をチェックするよりも少し時間がかかります。

+0

それはすべての 'NodeList'sに当てはまりますか、それとも生きているだけですか? –

+0

Thanks @Mike、コードはありますか?おそらく派生した質問は、「配列はどのようにJavascriptで実装されていますか? – santiagobasulto

+2

配列のMozillaの開発者ネットワークを見ると、長さhttps://developer.mozilla.org/ja/JavaScript/Reference/Global_Objects/Arrayの情報はあまりありませんが、長さを事前に計算して保存します変数だけで安全です。私はブラウザが同じJSエンジンを共有しているとは思わない。 –

2

アトリビュートの検索速度のために、ローカル変数の長さをキャッシュすることで、おそらく適度な速度向上が得られます。これは、JSエンジンがコードをどのようにJITするかに応じて、無視することもあれば無視することもできます。

初歩的なJSperfテストケースについては、http://jsperf.com/for-loop-cachingを参照してください。

+0

ありがとう@AKX、私は属性ルックアップを問題とは考えていません。 array.lengthを使用すると、物事を読みやすくできます。 – santiagobasulto

+1

これはあまり初歩的なjsperfテストケースです。http://jsperf.com/caching-array-length/4 – Tomalak

+0

良いテスト!私はそれ以上の反復ではない。私はそれを循環させるモジュラスを使っています。 – santiagobasulto

1

長さを操作したくないコレクションタイプのオブジェクト(不変コレクションなど)では、パフォーマンスを向上させるためにその長さをキャッシュすることをお勧めします。

var elems = document.getElementsByName("tst"); 
var elemsLen = elems.length; 
var i; 
for(i = 0; i < elemsLen; ++i) 
{ 
    // work with elems... example: 
    // elems[i].selected = false; 
} 
elems = [10,20,30,40,50,60,70,80,90,100]; 
elemsLen = elems.length; 
for(i = 0; i < elemsLen; ++i) 
{ 
    // work with elems... example: 
    // elems[i] = elems[i]/10; 
} 
+0

なぜですか?任意のコード?パフォーマンスのペナルティがない場合は、.lengthメソッドを使用する方が良いと思います。私はそれが私がそれを呼び出すたびに計算されていない場合、私は意味します。 – santiagobasulto

+1

@santiagobasulto 'length'プロパティが常に計算されるわけではないため、一部のブラウザではパフォーマンスが低下することは間違いありません。しかし、他のブラウザでは、変数へのキャッシングはループ内の 'length'プロパティにアクセスするよりも高速です。詳細はhttp://jsperf.com/for-loop-cachingを参照してください。次に、スクロールして、ループ内のプロパティを使用してアクセスするのではなく、「長さ」の値をキャッシュすると、IEとOperaのパフォーマンスが向上することに注意してください。 –

21

いつものように、答えは「それに依存します」です。

Let's test native arrays with a million-element array:

for (var i = 0; i < arr.length; i++); 

var len=arr.length; 
for (var i = 0; i < len; i++); 

http://josh3736.net/images/arrlen.png

ChromeとFirefoxのローカル変数に長さをコピーするほど効率的であるとプロパティアクセサを最適化します。 IEとOperaはそうではなく、50%以上遅いです。

しかし、テスト結果 『第二のops /』百万要素秒あたりの配列を完全な反復回数を意味していることに注意してください。

IE8(このバンチでは最悪の出演者)であっても、視点に入れて— .44と3を記録しました。9プロパティアクセスとローカル変数それぞれについて—反復ペナルティは僅かでした2μsです。 array.lengthを使用して1000個以上のアイテムを繰り返し処理すると、2ミリ秒かかるだけです。言い換えれば:早めの最適化を注意してください。

+0

+1それをパースペクティブに置く。 – Tomalak

+0

私はこの答えが大好きです。 –

+0

1,000個のアイテムに対して2ミリ秒を保存することは時期尚早の最適化ではありません。さらに10,000アイテムがあればどうなるでしょうか?コードが頻繁に呼び出される場合は? –

9

実際のアレイの長さはオンザフライでは計算されません。これは配列データ構造の一部として格納されるため、アクセスするのは値を取得するだけではありません(計算はありません)。そのため、一般に、オブジェクトの固定プロパティを取得するのと同じくらい速くなります。あなたはこのパフォーマンステストで見ることができるように、配列の長さを取得し、オブジェクトのプロパティを取得するに違いは基本的にありません:

http://jsperf.com/length-comparisons

この例外は、そのDOMリターンのNodeListオブジェクトでありますgetElementsByTagName()またはgetElementsByClassName()などの関数からこれらの場合、lengthプロパティにアクセスする方がずっと遅くなることがよくあります。これはおそらく、これらのnodeListオブジェクトが真のjavascriptオブジェクトではなく、これらのオブジェクトから何かにアクセスするたびに交差する必要があるJavascriptとネイティブコードの間にブリッジがあるためです。この場合、長さをローカル変数にキャッシュするのは、nodeListからのループで繰り返し使用するのではなく、ずっと高速です(10〜100倍速くなります)。私はそれを長さ比較に加えました。そしてあなたはそれがどれほど遅いかを見ることができます。

いくつかのブラウザでは、長さをローカル変数に入れて、それを何度も(ループのように)参照している場合は、そこから使用する方が意味があります。ここでは上記jsperfテストからパフォーマンスのグラフがあります: