私は本からこのようなループを書くべきであることを学びました:
for(var i=0, len=arr.length; i < len; i++){
// blah blah
}
そのため、arr.length
は毎回計算されません。
他の人たちは、コンパイラがこれに対していくらかの最適化をすると言うので、あなたはただ書くことができます:
for(var i=0; i < arr.length; i++){
// blah blah
}
どちらが実際に最良の方法であるかを知りたいだけですか?
最近のほとんどのブラウザでこのテストを実行した後...
現在、ループの最速形式(そして私の考えでは最も構文的に明白なもの)。
長さキャッシングを持つループの標準
for (var i = 0, len = myArray.length; i < len; i++) {
}
これは間違いなくJavaScriptエンジン開発者に拍手を送るケースです。実行時間は、明瞭度、賢さではないに最適化する必要があります。
JavaScriptの配列をループ処理する最も速い方法は次のとおりです。
var len = arr.length;
while (len--) {
// blah blah
}
完全な比較については、 http://blogs.Oracle.com/greimer/entry/best_way_to_code_a を参照してください。
2016年6月現在、最新のChrome(2016年5月のブラウザ市場の71%でテストが行われています):
このスレッドは古すぎるので、長さをキャッシュする必要があると考えるか、パフォーマンスを向上させるためにデクリメント付きの逆方向トラバースを使用する必要があると考えるのは誤解を招くようなプログラマーです。したがって、私はお勧めします:
あなたのアプリがたくさんの項目を繰り返し処理するか、あなたのループコードが頻繁に使われる関数の中にあるならば、単純なforループが答えです:
for (var i = 0; i < arr.length; i++) {
// Do stuff with arr[i] or i
}
あなたのアプリが実際にたくさんのアイテムを反復処理しない場合、あるいはあちこちで小さな反復処理を実行する必要がある場合は、標準のforEachコールバック、または選択したJSライブラリからの同様の関数を使用する方が理解しやすく、エラーを起こしにくいかもしれません。インデックス変数のスコープは閉じているので、角かっこを使用する必要はありません。配列の値に直接アクセスします。
arr.forEach(function(value, index) {
// Do stuff with value or index
});
何十億もの行を繰り返し処理している間に実際に数ミリ秒をスクラッチする必要があり、配列の長さがプロセスを通じて変わらない場合は、forループで長さをキャッシュすることを検討してください。今日ではこれは本当に必要ではないと思いますが。
for (var i = 0, len = arr.length; i < len; i++) {
// Do stuff with arr[i]
}
順序が重要ではない場合は、私はこのスタイルが好きです:
for(var i = array.length; i--; )
それは長さをキャッシュし、書くのはずっと短いです。しかし、それは逆の順序で配列を繰り返します。
たった2018なので更新はいいかもしれません...
そして私は本当に受け入れられた答えに同意しない必要があります。ブラウザによって異なります。いくつかはforEach
をより速く、いくつかのfor-loop
を、そしていくつかのwhile
はすべてのメソッドのベンチマークです http://jsben.ch/mW36e
arr.forEach( a => {
// ...
}
for(a = 0; ... )
のようにfor-loopがたくさんあるのを見ることができるので、 'var'変数がないとグローバルに定義され、これはスピードに劇的に影響するので、遅くなるでしょう。
var arr = arr = new Array(11111111).fill(255);
var benches =
[ [ "empty", () => {
for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
for(var a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
}]
, ["for-loop++", () => {
for(var a = 0, l = arr.length; a < l; a++)
var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
for(var a = 0; a < arr.length; ++a )
var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
for(var a = arr.length - 1; a >= 0; --a )
var b = arr[a] + 1;
}]
,["while-loop", () => {
var a = 0, l = arr.length;
while( a < l ) {
var b = arr[a] + 1;
++a;
}
}]
, ["reverse-do-while-loop", () => {
var a = arr.length - 1; // CAREFUL
do {
var b = arr[a] + 1;
} while(a--);
}]
, ["forEach", () => {
arr.forEach( a => {
var b = a + 1;
});
}]
, ["for..in (only 3.3%)", () => {
var ar = arr.slice(0,arr.length/33);
for( const a in ar ) {
var b = a + 1;
}
}]
, ["Duff's device", () => {
var i = 0;
var r = arr.length % 8;
var n = (arr.length - r) / 8;
if (r > 0) do {
var b = arr[i++] + 1;
}
while (--r);
if (n > 0) do {
var b = arr[i] + 1;
var c = arr[i+1] + 1;
var d = arr[i+2] + 1;
var e = arr[i+3] + 1;
var f = arr[i+4] + 1;
var g = arr[i+5] + 1;
var h = arr[i+6] + 1;
var k = arr[i+7] + 1;
i = --n >>> 3;
}
while (n);
}]
, ["Duff's device negative", () => {
var r = arr.length % 8;
var n = (arr.length-r) / 8; ///Math.floor(arr.length / 8);
var i = arr.length ; // -1;
while(r){
var b = arr[--i] + 1;
--r;
}
while(n){
var b = arr[i] + 1;
var c = arr[i-1] + 1;
var d = arr[i-2] + 1;
var e = arr[i-3] + 1;
var f = arr[i-4] + 1;
var g = arr[i-5] + 1;
var h = arr[i-6] + 1;
var j = arr[i-7] + 1;
i = --n >>> 3;
}
}]];
function bench(title, f) {
var t0 = performance.now();
var res = f();
return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
// Here if you forget to put 'var' so variables'll be global
for(a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
});
var times = benches.map( function(a) {
arr = new Array(11111111).fill(255);
return [a[0], bench(...a)]
}).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
`<div>` +
`<span>${title} </span>` +
`<span style="width:${3+n/2}%"> ${Number(time.toFixed(3))}msec</span>` +
`</div>`;
var strRes = times.map( t => template(...t) ).join("\n") +
`<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div { clear:both }
body > div > div > span {
float:left;
width:43%;
margin:3px 0;
text-align:right;
}
body > div > div > span:nth-child(2) {
text-align:left;
background:darkorange;
animation:showup .37s .111s;
-webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>
2014 While
が帰ってきました
論理的に考えてください。
これを見てください
for( var index = 0 , length = array.length ; index < length ; index++ ) {
//do stuff
}
for
ループには3つのパラメータがありますこれがなぜこれより速いのかを教えてください。
var length = array.length;
while( --length ) { //or length--
//do stuff
}
while
には1つのパラメータしかありませんChrome 28でforループの実行時間が早いことが判明したとき、私はまったく混乱しました。これはある種のベンベンを持っている必要があります
「えーと、誰もがforループを使っています。for chromeを開発する際には、そのことに集中しましょう。」
しかし今、2014年にはwhileループはクロムに戻りました。 2倍速く、他のブラウザや古いブラウザでは常に速いです。
最近私はいくつかの新しいテストを行いました。実社会の環境では、これらの短いコードは意味がなく、jsperfはwhileループを正しく実行できません。これには、array.lengthを再作成する必要があるため時間もかかります。
あなたはjsperf上でwhileループの実際の速度を得ることができません。
あなたはあなた自身のカスタム関数を作成し、window.performance.now()
でそれをチェックする必要があります
ええと…whileループを単純に速くする方法はありません。
本当の問題は、実際にはDOMの操作/レンダリング時間/描画時間です。
例えば、私は座標と衝突を計算する必要があるキャンバスシーンを持っています...これは10-200マイクロ秒の間に行われます(ミリ秒ではありません)。 DOMと同じように、実際にすべてをレンダリングするのに数ミリ秒かかります。
BUT
場合によっては、for loop
を使用したもう1つの優れた方法があります。
for(
var i = array.length ;
i > 0 ;
arrayCopy[ --i ] = array[ i ] // doing stuff
);
パラメータの設定に注意してください。
これは、マシンが - のようであることを確認するということを言いました
もう少し短くして無駄なものを取り除き、同じスタイルを使ってこれを書いたと書いています。
for(
var i = array.length ;
i-- ;
arrayCopy[ i ] = array[ i ] // doing stuff
);
たとえもっと短くてもi
を使うともう一度遅くなります。前のfor
ループとwhile
ループよりも1/5遅くなります。
注:;
がないfor loooの後は、{}
が非常に重要です。
Jsperfはスクリプトをテストする最良の方法ではないと私が言ったとしても、この2つのループをここに追加しました。
http://jsperf.com/caching-array-length/4
そしてここにJavaScriptのパフォーマンスについての別の答えがあります
https://stackoverflow.com/a/21353032/24507
この答えはjavascriptを書くのに効果的な方法を示すことです。あなたがそれを読むことができないのであれば、尋ねるとあなたは答えを得るか、またはJavaScriptについての本を読む http://www.ecma-international.org/ecma-262/5.1/
http://jsperf.com/caching-array-length/6
私が(古いものを再利用することによって)準備したtestの最新版は、一つのことを示しています。
キャッシングの長さはそれほど重要ではありませんが、害はありません
私のDebian Squeeze 64ビット版では、Chrome、Opera、Firefoxの4つのスニペット(チャートでは3、5、7、10)目で、上のリンクを(最初に開いたタブで)最初に実行するたびに最良の結果が得られます( 私のデスクトップハードウェア )。後続の実行ではまったく異なる結果が得られます。
パフォーマンス面での結論は簡単です。
!==
の代わりに<
を使用してテストします。shift()
配列に対するwhileループも効率的です。tl; dr
パターンの下の今日(2011.10)は最速のもののようです。
for (var i = 0, len = arr.length; i !== len; i++) {
...
}
arr.length
をキャッシュすることはここでは重要ではないので、i !== arr.length
をテストするだけでパフォーマンスは低下しませんが、コードが短くなります。
PS:shift()
のスニペットでは、0番目の要素にアクセスする代わりにその結果を使用できることはわかっていますが、以前のリビジョン(ループ中に間違っていた)を再利用した後.
純粋なパフォーマンスのように「最高」?またはパフォーマンスおよびの可読性?
純粋なパフォーマンス「最高の」これは、キャッシュと++プレフィックス演算子を使用する(私のデータ: http://jsperf.com/caching-array-length/189 )
for (var i = 0, len = myArray.length; i < len; ++i) {
// blah blah
}
私は、キャッシュレスforループが実行時間とプログラマーの読み取り時間の間で最良のバランスであると主張するでしょう。 C/C++/Javaで始まったすべてのプログラマーはこれを通読しなければならないmsを無駄にしません
for(var i=0; i < arr.length; i++){
// blah blah
}
**ループの内側に配列の長さをキャッシュすると、数秒の時間がかかります。配列内の項目数が多い場合は、配列内の項目に依存します。
**
sArr; //Array[158];
for(var i = 0 ; i <sArr.length ; i++) {
callArray(sArr[i]); //function call
}
***end: 6.875ms***
**
**
sArr; //Array[158];
for(var i = 0,len = sArr.length ; i < len ; i++) {
callArray(sArr[i]); //function call
}
***end: 1.354ms***
**
これ 最速の方法に見える はるかに...
var el;
while (el = arr.shift()) {
el *= 2;
}
これが配列を消費し、それを食べ、そして何も残さないことを考慮に入れてください...
2017年です2017。
私はいくつかテストをしました。
https://jsperf.com/fastest-way-to-iterate-through-an-array/
while
メソッドがChromeで最も速いようです。
Firefoxの左の減少(--i
)は他のもの(++i
、i--
、i++
)よりはるかに速いように見えます。
このアプローチは平均して断食です。しかし、それは逆の順序で配列を繰り返します。
let i = array.length;
while (--i >= 0) {
doSomething(array[i]);
}
順方向が重要な場合は、この方法を使用してください。
let ii = array.length;
let i = 0;
while (i < ii) {
doSomething(array[i]);
++i;
}
私はいつも最初のスタイルで書いています。
たとえコンパイラがそれを配列用に最適化するのに十分スマートであったとしても、それでもここでDOMNodeListまたは計算された長さを持つ複雑なオブジェクトを使用しているならばそれでもスマートですか?
配列に関する問題はわかっていますが、すべてのループを1つのスタイルで記述するのは得策です。
var arr = []; // The array
var i = 0;
while (i < arr.length) {
// Do something with arr[i]
i++;
}
i ++は++ i、 - i、i--より速いです
また、最後にiにアクセスする必要があるときにarr [i ++]を実行して最後の行を保存することもできます(ただし、これはデバッグが難しい場合があります)。
あなたはここでそれをテストすることができます(他のループテストで): http://jsperf.com/for-vs-whilepop/5
私は巨大な配列を繰り返すために他の方法を試してみましたが、配列の長さを半分にしてから両方の半分を単一のループで繰り返す方が速いことがわかりました。このパフォーマンスの違いは、処理中に見られます巨大な配列。
var firstHalfLen =0;
var secondHalfLen = 0;
var count2=0;
var searchterm = "face";
var halfLen = arrayLength/2;
if(arrayLength%2==halfLen)
{
firstHalfLen = Math.ceil(halfLen);
secondHalfLen=Math.floor(halfLen);
}
else
{
firstHalfLen=halfLen;
secondHalfLen=halfLen;
}
for(var firstHalfCOunter=0,secondHalfCounter = arrayLength-secondHalfLen;
firstHalfCOunter < firstHalfLen;
firstHalfCOunter++)
{
if(mainArray[firstHalfCOunter].search(new RegExp(searchterm, "i"))> -1)
{
count2+=1;
}
if(secondHalfCounter < arrayLength)
{
if(mainArray[secondHalfCounter].search(new RegExp(searchterm, "i"))> -1)
{
count2+=1;
}
secondHalfCounter++;
}
}
キャッシュされた長さのfor-loop VSと上記の方法のパフォーマンス比較(timer.jsを使用)。
私が知っている最もエレガントな解決策は地図を使うことです。
var arr = [1,2,3];
arr.map(function(input){console.log(input);});
Whileループはforループより少し速いです。
var len = arr.length;
while (len--) {
// blah blah
}
代わりにwhileループを使う
基本的なwhileループが最速です。 jsperf.comは、この種の概念をテストするための優れたサンドボックスです。
別のjsperf.comテスト: http://jsperf.com/while-reverse-vs-for-cached-length
逆のwhileループが最も速いようです。唯一の問題は、while(--i)が0で停止することです。それでは、ループ内でarray [0]にアクセスするにはどうすればよいですか。
2017年9月現在 これらのjsperfテスト は、Chrome 60上で最もパフォーマンスが良いとされる次のパターンを示しています。
function foo(x) {
x;
};
arr.forEach(foo);
誰でも再現することができますか?
これを試して:
var myarray =[],
i = myarray.lenght;
while(i--){
// do somthing
}
2019年以降、WebWorkerはより大きな人気を博しています。大規模なデータセットでは、マルチコアプロセッサをフルに活用することで、WebWorkerを使用してはるかに高速に処理できます。
また、 Parallel.js があるので、WebWorkerはデータ処理にはるかに使いやすくなります。