これを何度も聞いたことがあります。逆方向にカウントするときにJavaScriptループは本当に高速ですか?もしそうなら、なぜですか?リバースループの方が速いことを示すテストスイートの例をいくつか見てきましたが、その理由についての説明が見つかりません。
ループが終了したかどうかを確認するたびにプロパティを評価する必要がなくなり、最終的な数値に対してチェックするだけだからだと思います。
つまり.
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
i--
がi++
より速いというわけではありません。実際、どちらも同等に高速です。
昇順ループに時間がかかるのは、各i
について、配列のサイズを評価することです。このループ内:
for(var i = array.length; i--;)
i
を宣言するときに.length
を評価するのは1回だけですが、このループでは
for(var i = 1; i <= array.length; i++)
.length
をチェックするときに、i
をインクリメントするたびにi <= array.length
を評価します。
ほとんどの場合、あなたはこの種の最適化についても心配する必要はありません。
私はこの答えで全体像を説明しようとします。
カッコ内の次の考えは問題を最近テストするまで私の信念でした:
[[低レベル言語に関しては C / C++ のように、コードは変数がゼロ(またはゼロ以外)のときに、プロセッサが特別な条件付きジャンプコマンドを持つようにコンパイルされています。
また、これほど多くの最適化を気にする場合は、++i
がシングルプロセッサコマンドであるのに対し、i++
は++i
を意味するため、i++
の代わりにj=i+1, i=j
を使用できます。]]
非常に高速なループは、展開することで実行できます。
for(i=800000;i>0;--i)
do_it(i);
それよりもずっと遅いことがあります
for(i=800000;i>0;i-=8)
{
do_it(i); do_it(i-1); do_it(i-2); ... do_it(i-7);
}
しかし、これの理由は非常に複雑になる可能性があります(言うまでもなく、プロセッサコマンドの前処理とゲーム内のキャッシュ処理の問題があります)。
高レベル言語に関しては、 JavaScript のように、ライブラリに依存している場合は最適化でき、ループ用の関数内。最善の方法を決定してもらいます。
したがって、JavaScriptでは、次のようなものを使用することをお勧めします。
array.forEach(function(i) {
do_it(i);
});
また、エラーが発生しにくく、ブラウザでコードを最適化する機会があります。
[注:ブラウザだけでなく、あなたも簡単に最適化するスペースがあります。forEach
関数(ブラウザ依存)を再定義して、最新の最高のトリックを使用してください! :) @ A.M.K。特別な場合には、array.pop
またはarray.shift
を使用する価値があります。その場合は、カーテンの後ろに置きます。 最大限の過剰は、forEach
にオプションを追加してループアルゴリズムを選択することです。]
さらに、低レベル言語でも、可能な場合は、複雑なループ操作にスマートライブラリ関数を使用することをお勧めします。
これらのライブラリは、物事をマルチスレッド化して背中に置くこともでき、専門のプログラマーがそれらを最新の状態に保ちます。
私はもう少し詳しく調べましたが、C/C++では、5e9 =(50,000x100,000)の操作であっても、上下に違いはありません@alestanisのような定数に対してテストが行われた場合。 (JsPerfの結果は一貫していない場合がありますが、概して同じことを言っています。大きな違いを生むことはできません。)
そのため、--i
はむしろ「ポッシュ」なものです。それはあなたがより良いプログラマのように見えるようにするだけです。 :)
一方、この5e9状況での展開では、10秒進むと12秒から2.5秒になり、20秒になると2.1秒になりました。最適化が行われなかったため、最適化によって測定不能な短い時間になりました。 :)(アンロールは上記の方法またはi++
を使用して行うことができますが、JavaScriptで先に進むことはありません。)
全体として:i--
/i++
と++i
/i++
の就職面接の違いを維持し、利用可能な場合はarray.forEach
またはその他の複雑なライブラリ関数に固執します。 ;)
i--
はi++
と同じくらい高速です
以下のこのコードはあなたのものと同じくらい高速ですが、追加の変数を使用します:
var up = Things.length;
for (var i = 0; i < up; i++) {
Things[i]
};
毎回配列のサイズを評価しないことをお勧めします。大きなアレイの場合、パフォーマンスの低下が見られます。
このテーマに興味があるので、JavaScriptループベンチマークに関するGreg Reimerのブログ投稿をご覧ください。JavaScriptでループをコーディングする最も速い方法は何ですか?:
JavaScriptでループをコーディングするさまざまな方法のためのループベンチマークテストスイートを構築しました。これらは既にいくつかありますが、ネイティブ配列とHTMLコレクションの違いを認めるものは見つかりませんでした。
また、https://blogs.Oracle.com/greimer/resource/loop-test.html
を開くことにより、ループのパフォーマンステストを実行できます(たとえば、ブラウザでJavaScriptが NoScript )。
編集:
Milan Adamovskyによって作成されたより最近のベンチマークは、実行時に here さまざまなブラウザーで実行できます。
var i, result = 0;
for (i = steps - 1; i; i--) {
result += i;
}
次が先行する最速として:
var result = 0;
for (var i = steps - 1; i >= 0; i--) {
result += i;
}
--
や++
ではなく、比較操作です。 --
では、0との比較を使用できますが、++
では、長さと比較する必要があります。プロセッサ上では、ゼロとの比較は通常利用可能ですが、有限整数との比較には減算が必要です。
a++ < length
実際にコンパイルされます
a++
test (a-length)
そのため、コンパイル時にプロセッサ上で時間がかかります。
通常のコード、特に JavaScript のような高級言語では、i++
とi--
にパフォーマンスの違いはありません。
パフォーマンス基準は、for
ループおよびcompareステートメントでの使用です。
これはすべての高レベル言語に適用され、JavaScriptの使用からほとんど独立しています。説明は、最終的な結果のアセンブラコードです。
ループでパフォーマンスの違いが発生する場合があります。背景は、アセンブラコードレベルでは、compare with 0
は追加のレジスタを必要としない1つのステートメントであることがわかります。
この比較は、ループのすべてのパスで発行され、測定可能なパフォーマンスの改善をもたらす可能性があります。
for(var i = array.length; i--; )
次のような擬似コードに評価されます。
i=array.length
:LOOP_START
decrement i
if [ i = 0 ] goto :LOOP_END
... BODY_CODE
:LOOP_END
はリテラル、つまり定数値であることに注意してください。
for(var i = 0 ; i < array.length; i++ )
次のような擬似コードに評価されます(通常のインタープリター最適化が想定されます):
end=array.length
i=0
:LOOP_START
if [ i < end ] goto :LOOP_END
increment i
... BODY_CODE
:LOOP_END
endは CPU レジスタを必要とする変数であることに注意してください。これにより、コードで追加のレジスタスワッピングが呼び出され、if
ステートメントでより高価な比較ステートメントが必要になります。
高級言語では、パフォーマンスをわずかに改善するため、保守性を促進する読みやすさがより重要です。
通常、配列startからendへのclassic反復の方が優れています。
配列endからstartへのより速い反復は、望ましくない逆のシーケンスになる可能性があります。
コメントで尋ねられたように:--i
とi--
の違いは、デクリメントの前または後のi
の評価にあります。
最良の説明は、試してみることです;-)ここに Bash の例を示します。
% i=10; echo "$((--i)) --> $i"
9 --> 9
% i=10; echo "$((i--)) --> $i"
10 --> 9
Sublime Text 2にも同じ推奨事項があります。
すでに述べたように、主な改善点は、forループの各反復で配列の長さを評価しないことです。これはよく知られた最適化手法であり、配列がHTMLドキュメントの一部である場合にJavaScriptで特に効率的です(すべてのfor
要素に対してli
を実行します)。
例えば、
for (var i = 0; i < document.getElementsByTagName('li').length; i++)
よりずっと遅い
for (var i = 0, len = document.getElementsByTagName('li').length; i < len; i++)
私が立っている場所から、あなたの質問のフォームの主な改善点は、余分な変数(私の例ではlen
)を宣言しないという事実です
しかし、あなたが私に尋ねると、ポイントはi++
対i--
最適化についてではなく、各反復で配列の長さを評価する必要がないことです( jsperf でベンチマークテストを見ることができます)。
他の回答はどれもあなたの特定の質問に答えていないようです(そのうち半数以上がCの例を示しており、低レベル言語について話し合っているので、あなたの質問はJavaScriptに関するものです)。
だから、ここに行きます:
簡単な答え:i--
は、実行するたびに0との比較を実行する必要がないため、一般に高速です。さまざまなメソッドのテスト結果は以下のとおりです。
テスト結果:this jsPerfで「証明」されているように、arr.pop()
は実際には最速のループです。しかし、質問で尋ねたように、--i
、i--
、i++
、および++i
に注目すると、jsPerf(これらは複数のjsPerfのものです。以下のソースを参照してください)の結果を要約します。
--i
とi--
はFirefoxで同じですが、i--
はChromeで高速です。
Chromeでは、基本的なforループ(for (var i = 0; i < arr.length; i++)
)はi--
および--i
より高速ですが、Firefoxでは低速です。
ChromeとFirefoxの両方で、キャッシュされたarr.length
は、Chromeで約170,000 ops/secだけ先行しているため、非常に高速です。
重大な違いはありませんが、++i
はほとんどのブラウザでi++
よりも高速です、私の知る限り、どのブラウザでも他の方法ではありません。
短い要約:arr.pop()
は断然最速のループです。特に言及したループの場合、i--
が最速のループです。
出典:http://jsperf.com/fastest-array-loops-in-javascript/15 、 http://jsperf.com/ipp-vs-ppi-2
これがあなたの質問に答えることを願っています。
JavaScriptでi--
がi++
より速いと言っても意味がないと思います。
まず第一に、JavaScriptエンジンの実装に完全に依存します。
第二に、最も単純な構成がJITされ、ネイティブ命令に変換される場合、i++
対i--
は、それを実行するCPUに完全に依存します。つまり、ARM(携帯電話)では、1つの命令でデクリメントとゼロとの比較が実行されるため、0に下がる方が高速です。
おそらく、あなたは、提案された方法が
for(var i = array.length; i--; )
しかし、提案された方法は、一方が他方よりも速いためではなく、単にあなたが書く場合
for(var i = 0; i < array.length; i++)
その後、毎回array.length
を評価する必要がありました(よりスマートなJavaScriptエンジンは、おそらくループが配列の長さを変更しないことを理解できます)。単純なステートメントのように見えますが、実際には、JavaScriptエンジンによって内部で呼び出される関数です。
i--
を「高速」と見なすことができるもう1つの理由は、JavaScriptエンジンがループを制御するために1つの内部変数(var i
への変数)のみを割り当てる必要があるためです。 array.lengthまたは他の変数と比較した場合、ループを制御するために複数の内部変数が必要であり、内部変数の数はJavaScriptエンジンの制限された資産です。ループで使用される変数が少ないほど、JITが最適化する可能性が高くなります。 i--
がより高速であると考えられるのはそのためです...
メモリ内のアレイの配置と、そのアレイにアクセスしている間のメモリページのヒット率に依存します。
場合によっては、ヒット率が向上するため、列順序で配列メンバーにアクセスする方が行順序よりも高速になります。
最後に気になったのは、 6502 Assembly(8-bit、yeah!)と書いているときでした。大きな利点は、ほとんどの算術演算(特にデクリメント)が一連のフラグを更新したことで、そのうちの1つはZ
(「リーチゼロ」インジケーター)でした。
したがって、ループの最後で、DEC
(デクリメント)とJNZ
(ゼロでない場合はジャンプ)の2つの命令を実行しただけで、比較は不要です。
手短に言うと:JavaScriptでこれを行うことにまったく違いはありません。
まず、自分でテストできます。
JavaScriptライブラリのスクリプトをテストおよび実行できるだけでなく、以前に記述された一連のスクリプト全体にアクセスしたり、さまざまなプラットフォームのさまざまなブラウザーで実行時間の違いを確認したりすることもできます。
したがって、ご覧のとおり、どの環境でもパフォーマンスに違いはありません。
スクリプトのパフォーマンスを改善する場合は、次のことを試してください。
var a = array.length;
ステートメントを用意しますしかし、あなたが得ることができる改善は非常に取るに足らないものであり、たいていそれを気にする必要さえないことを理解しなければなりません。
ずいぶん前に、共通の機械命令DSZ(ゼロでデクリメントおよびスキップ)がありました。アセンブリ言語でプログラミングした人々は、この命令を使用して、レジスターを保存するためにループを実装しました。今、この古代の事実は時代遅れであり、この疑似改善を使用して、どの言語でもパフォーマンスの改善は得られないでしょう。
私たちの時代にそのような知識を広めることができる唯一の方法は、他人の個人コードを読むときだと思います。そのような構造を見て、なぜそれが実装されたのかを尋ね、ここで答えは「ゼロに比べてパフォーマンスが向上する」ということです。あなたは同僚のより高い知識に戸惑い、それをもっと賢くするためにそれを使うと思うようになりました:-)
これは--
または++
符号に依存しませんが、ループで適用する条件に依存します。
例:配列の長さやその他の条件など、ループが毎回条件をチェックする場合よりも、変数に静的な値がある場合、ループは高速です。
ただし、この最適化について心配する必要はありません。今回はその効果がナノ秒単位で測定されるためです。
for(var i = array.length; i--; )
はそれほど高速ではありません。しかし、array.length
をsuper_puper_function()
に置き換えると、大幅に速くなる場合があります(すべての反復で呼び出されるため)。それが違いです。
2014年に変更する場合は、最適化について考える必要はありません。 「検索と置換」を使用して変更する場合、最適化について考える必要はありません。時間がない場合は、最適化について考える必要はありません。しかし、今、あなたはそれについて考える時間があります。
追伸:i--
はi++
よりも高速ではありません。
JavaScript(およびすべての言語)が最終的にCPUで実行されるオペコードに変換されることで説明できます。 CPUは常にゼロと比較するための単一の命令を持っていますが、これは非常に高速です。
余談ですが、count
が常に>= 0
であることを保証できる場合は、次のように単純化できます。
for (var i = count; i--;)
{
// whatever
}
jsbenchでの比較 を作成しました。
Alestaniが指摘したように、昇順のループに時間がかかることの1つは、反復ごとに配列のサイズを評価することです。このループ内:
for ( var i = 1; i <= array.length; i++ )
i
をインクリメントするたびに.length
を評価します。これで:
for ( var i = 1, l = array.length; i <= l; i++ )
i
を宣言するときに、.length
を一度だけ評価します。これで:
for ( var i = array.length; i--; )
比較は暗黙的であり、i
をデクリメントする直前に行われ、コードは非常に読みやすくなります。ただし、大きな違いを生むことができるのは、ループ内に配置するものです。
関数を呼び出すループ(別の場所で定義):
for (i = values.length; i-- ;) {
add( values[i] );
}
インラインコードでループします。
var sum = 0;
for ( i = values.length; i-- ;) {
sum += values[i];
}
読みやすさを犠牲にすることなく、関数を呼び出す代わりにコードをインライン化できる場合、ループを1桁速くすることができます!
注:ブラウザは インライン化が上手になりました 単純な関数なので、コードの複雑さに大きく依存します。したがって、最適化する前にプロファイルを作成します。なぜなら、
でも覚えておいて:
コードは人々が読むために書かれており、偶然にマシンが実行されるためだけに書かれています。
コードの記述方法に非常に小さな変更を加えると、コードの実際の実行速度に大きな違いが生じることがあります。小さなコードの変更が実行時間に大きな違いをもたらす可能性のある領域の1つは、配列を処理するforループがある場所です。配列がWebページ上の要素(ラジオボタンなど)の場合、変更が最大の効果をもたらしますが、配列がJavascriptコードの内部にある場合でもこの変更を適用する価値があります。
Forループをコーディングして配列を処理する従来の方法は、次のようになります。
for (var i = 0; i < myArray.length; i++) {...
この問題は、myArray.lengthを使用して配列の長さを評価するのに時間がかかり、ループをコーディングする方法がこの評価をループのたびに実行する必要があることを意味することです。配列に1000個の要素が含まれている場合、配列の長さは1001回評価されます。ラジオボタンを見てmyForm.myButtons.lengthがあった場合、ループのたびに長さを評価する前に、指定したフォーム内の適切なボタンのグループを最初に見つける必要があるため、評価にさらに時間がかかります。
明らかに、処理中に配列の長さが変化することはないので、これらの長さの再計算はすべて、処理時間に不必要に追加されるだけです。 (もちろん、配列エントリを追加または削除するコードがループ内にある場合、配列サイズは反復間で変化する可能性があるため、それをテストするコードを変更することはできません)
サイズが固定されているループでこれを修正するためにできることは、ループの開始時に一度長さを評価し、変数に保存することです。その後、変数をテストして、ループを終了するタイミングを決定できます。これは、特に配列に数個以上のエントリが含まれている場合、またはWebページの一部である場合に、毎回配列の長さを評価するよりもはるかに高速です。
これを行うコードは次のとおりです。
for (var i = 0, var j = myArray.length; i < j; i++) {...
そのため、今度は配列のサイズを1回だけ評価し、ループのたびにその値を保持する変数に対してループカウンターをテストします。この追加の変数は、配列のサイズを評価するよりもはるかに高速にアクセスできるため、コードは以前よりもはるかに高速に実行されます。スクリプトには1つの追加変数があります。
多くの場合、配列内のすべてのエントリが処理される限り、配列の処理順序は関係ありません。この場合、追加したばかりの余分な変数を廃止し、逆の順序で配列を処理することで、コードをわずかに高速化できます。
配列を可能な限り最も効率的な方法で処理する最終コードは次のとおりです。
for (var i = myArray.length-1; i > -1; i--) {...
このコードは、開始時に一度だけ配列のサイズを評価しますが、ループカウンターを変数と比較する代わりに、定数と比較します。定数は変数よりもアクセスに効果的であり、割り当てステートメントが1つ少ないため、コードの3番目のバージョンは2番目のバージョンよりもわずかに効率的であり、最初のバージョンよりもはるかに効率的です。
あなたが今それをしている方法は高速ではありません(無限ループであることを除けば、i--
を行うつもりだったと思います)。
より高速にしたい場合は、以下を実行します。
for (i = 10; i--;) {
//super fast loop
}
もちろん、このような小さなループでは気付かないでしょう。高速である理由は、「true」であることを確認しながらiをデクリメントするためです(0に達すると「false」と評価されます)
使用済み --iは(C++で)より高速だったと言われるのは、値が1つしか減少しないためです。 i--は、デクリメントされた値をiに保存し、元の値を結果として保持する必要があります(j = i--;)。ほとんどのコンパイラでは、1つではなく2つのレジスタを使用していたため、別の変数をレジスタ変数として保持するのではなく、メモリに書き込む必要がありました。
最近は違いはないと言っている他の人たちに同意します。
I--またはi ++によって多くの時間が消費されることはありません。 CPUアーキテクチャの奥深くに行くと、++
オペレーションは2の補数を行うため、--
は--
よりも高速ですが、ハードウェア内で発生したため、++
と--
の間に大きな違いはありません操作は、CPUで消費される最小時間と見なされます。
for loopは次のように実行されます。
<
、>
、<=
などの制約を確認します。そう、
for (var i = Things.length - 1; i >= 0; i--) {
Things[i]
};
開始時に一度だけ配列の長さを計算しますが、これはそれほど時間ではありませんが、
for(var i = array.length; i--; )
各ループで長さを計算するため、多くの時間が消費されます。
JavaScriptはコンパイルされた言語ではなくインタープリター言語であるため、++
と--
は関係ありません。各命令は複数の機械語に翻訳されるので、面倒な詳細を気にする必要はありません。
--
(または++
)を使用してアセンブリ命令を効率的に使用することについて話している人々は間違っています。これらの命令は整数演算に適用され、 JavaScriptに整数はなく、数字のみ があります。
読み取り可能なコードを記述する必要があります。
とても簡単な言葉で
「i--とi ++。実際、どちらも同じ時間がかかります」。
ただし、この場合、インクリメンタル操作を行う場合..変数が1ずつ増加するたびにプロセッサが.lengthを評価し、デクリメントの場合は特にこの場合、0になるまで.lengthを1回だけ評価します。
多くの場合、これはプロセッサが他の比較よりも速くゼロと比較できるという事実と本質的には関係ありません。
これは、 少数のJavascriptエンジンのみ (JITリストにあるもの)が実際に機械語コードを生成するためです。
ほとんどのJavascriptエンジンは、ソースコードの内部表現を作成してから解釈します(これがどのようなものかを知るには、 FirefoxのSpiderMonkeyのこのページ の下部をご覧ください)。一般に、コードの一部が実質的に同じことを行うが、内部表現がより単純になる場合、それはより速く実行されます。
変数から変数を加算/減算する、または変数を何かと比較するなどの単純なタスクでは、インタープリターが内部の「命令」から次の命令に移動するオーバーヘッドが非常に高くなるため、以下の「命令」 JSエンジンによって内部的に使用される方が良いです。
まず、i++
とi--
は、JavaScriptを含むすべてのプログラミング言語でまったく同じ時間がかかります。
次のコードは時間がかかります。
高速:
for (var i = 0, len = Things.length - 1; i <= len; i++) { Things[i] };
遅い:
for (var i = 0; i <= Things.length - 1; i++) { Things[i] };
したがって、次のコードも時間がかかります。
高速:
for (var i = Things.length - 1; i >= 0; i--) { Things[i] };
遅い:
for (var i = 0; i <= Things.length - 1; i++) { Things[i] };
追伸Slowは、コンパイラの最適化のため、一部の言語(JavaScriptエンジン)でのみ低速です。最善の方法は、代わりに '<'を使用することです '<='(または '=')および '-i'の代わりに 'i-- '。
JavaScriptについてはわかりません。実際には配列の長さの再評価と連想配列に関係するかもしれません(デクリメントするだけなら、新しいエントリを割り当てる必要はないでしょう。配列は密です。つまり、誰かがそのために最適化するかもしれません。
低レベルアセンブリには、DJNZと呼ばれるループ命令があります(ゼロ以外の場合はデクリメントおよびジャンプします)。したがって、デクリメントとジャンプはすべて1つの命令で行われ、INCおよびJL/JBよりもはるかに高速になる可能性があります(インクリメント、以下の場合はジャンプ/未満の場合はジャンプ)。また、ゼロとの比較は、別の数値との比較よりも簡単です。しかし、それは本当にわずかであり、ターゲットアーキテクチャにも依存します(たとえば、スマートフォンのArmで違いが生じる可能性があります)。
この低レベルの違いがインタープリター言語にそれほど大きな影響を与えるとは思わないでしょう。DJNZを回答の中に見たことがないので、面白い考えを共有すると思いました。
これは推測に過ぎませんが、別の値(i <Things.length)ではなく、プロセッサが0(i> = 0)と比較する方が簡単だからかもしれません。
コンパイラは.lengthをキャッシュしないので、0または.lengthを比較しても違いはありませんか?これは、あなたが扱っているコンパイラーまたはインタープリターに非常に特有なものだと思います。
最適化されたコンパイラまたはインタープリターを使用している場合、これについて心配する必要はありません。言語開発者が心配する必要があります。
この種の質問に答える最良の方法は、実際に試すことです。 100万回の繰り返しなどをカウントするループを設定し、両方の方法で実行します。両方のループの時間を計り、結果を比較します。
答えはおそらく、使用しているブラウザによって異なります。一部の結果は他とは異なります。
他の人が頭痛を避けるのを助ける---これに投票してください!!!
このページで最も人気のある回答はFirefox 14では機能せず、jsLinterを通過しません。 「while」ループには、割り当てではなく比較演算子が必要です。クロム、サファリ、さらにはIEでも機能します。しかし、Firefoxで死にます。
これはIS壊れています!
var i = arr.length; //or 10
while(i--)
{
//...
}
これは動作します! (firefoxで動作し、jsLinterを渡します)
var i = arr.length; //or 10
while(i>-1)
{
//...
i = i - 1;
}
それを愛し、多くのマークアップがありますが、答えはありません:D
ゼロと比較するだけで、常に最速の比較になります
(a == 0)は(a == 5)よりもTrueを返すのが実際に速いです
小さくて取るに足らないもので、コレクションに1億行あるので測定可能です。
つまり、ループ上で、i <= array.lengthであり、iをインクリメントしていると言っているかもしれません
ダウンループでは、i> = 0の場所で、代わりにiをデクリメントします。
比較は迅速です。ループの「方向」ではありません。
前置インクリメント演算子を使用すると、多少速くなります。接尾辞を使用すると、コンパイラは式の結果として以前の値を保持する必要があります。
for (var i = 0; i < n; ++i) {
do_stuff();
}
スマートインタープリターまたはコンパイラーは、i ++の結果が使用されず、式の結果を保存しないことを確認しますが、すべてのjsエンジンが保存するわけではありません。
私はこのスレッドに、クロスブラウザーであるJavaScriptの最速のループに貢献したいと思います!このループは、リバースwhileループと比較して500%以上の改善をもたらします。