36

先日の技術面接で、「Javascript コードを最適化するにはどうすればよいですか?」という質問がありました。

驚いたことに、彼は通常、while ループは for ループよりも高速であると言いました。

それは本当ですか?はいの場合、それはなぜですか?

4

5 に答える 5

43

while負のループがさらに高速になると反論する必要がありました。参照: JavaScript ループのパフォーマンス - イテレータを 0 に向けてデクリメントする方が、インクリメントするよりも速いのはなぜですか

whilevsではfor、これら 2 つのソースは、さまざまなブラウザーでさまざまなループを実行し、結果をミリ秒単位で比較することによって、速度現象をかなりよく文書化しています: https://blogs.oracle.com/greimer/entry/best_way_to_code_aおよび: http://www.stoimen .com/blog/2012/01/24/javascript-performance-for-vs-while/ .

概念的には、forループは基本的にパッケージ化されたwhileループであり、インクリメントまたはデクリメント (何らかの順序または長さに従ってロジックを進行させる) に特化したものです。例えば、

for (let k = 0; ++k; k < 20) {…}

負の while ループにすることで高速化できます。

var k = 20;
while (--k) {…}

上記のリンクの測定値からわかるように、節約された時間は実際には非常に大きな数になります.

于 2014-07-30T21:21:15.273 に答える
17

これは、速度と効率を細かく検出するための優れた答えですが、@Pointyの元のステートメントに戻る必要があります。

正しい答えは、V8 または SpiderMonkey への次のチェックインまでに、そのような最適化に費やした努力が完全に無駄になる可能性があるため、そのような詳細について心配することは一般的に無意味であるということです。

Javascript はクライアント側で決定され、クロスブラウザーの完全な互換性のためにブラウザーごとにコーディングする必要があったため (ECMA が関与する前はもっと悪かった)、大幅な最適化により、現時点では速度の違いは論理的な答えでさえない可能性があります。ブラウザとそのコンパイラ エンジンでの Javascript の採用。

GAS でのアプリケーションなど、非厳密なスクリプトのみの記述についても話しているわけではないため、答えや質問は楽しいものですが、実際のアプリケーションで役立つというよりも、おそらく些細なことです。

このトピックについて詳しく説明するには、まずこのトピックがどこから来ているのか、コンパイルと解釈の違いを理解する必要があります。言語の進化の歴史を簡単に見てから、コンパイルと解釈に戻りましょう。読む必要はありませんが、すぐに答えを得るために Compiling vs Interpeting を読むことができますが、より深く理解するために Compiling vs Interpreting と Evolution of Programming (それらが今日どのように適用されているかを示しています) の両方を読むことをお勧めします。

コンパイルと解釈

コンパイル済み言語コーディングは、コンパイラが理解できるコンパイル可能な方法でコードを記述するプログラミング方法です。現在、より認識されている言語のいくつかは、Java、C++、および C# です。これらの言語は、コンパイラ プログラムがコードをターゲット マシンで使用されるマシン コードまたはバイトコードに変換することを目的として記述されています。

解釈されたコードはJust I n T
処理されるコードです最初にコンパイルせずに実行時に ime (JIT) を使用すると、このステップをスキップして、より迅速な書き込み、デバッグ、追加/変更などを行うことができます。また、将来の使用のためにスクリプトの解釈を保存することはなく、メソッドが呼び出されるたびにスクリプトを実行します。解釈されたコードは、定義された意図されたプログラム ランタイム環境 (javascript は通常ブラウザーです) 内で実行され、環境によって解釈されると、目的の結果が出力されます。解釈されたスクリプトは、スタンドアロンのソフトウェアであることを意図したものではなく、常に解釈される有効なランタイム環境にプラグインしようとします。これが、スクリプトが実行できない理由です。オペレーティング システムと直接通信することはありません。発生しているシステム プロセスを見ると、スクリプトが処理されていることがわかりません。

したがって、Javascript で hello スクリプトを記述するということは、ブラウザがコードを解釈し、hello とは何かを定義し、これが発生している間、ブラウザはこのコードを機械レベルのコードに変換して、このスクリプトがあり、環境が hello という単語を表示したいということを意味します。次に、マシンはそれを処理して、スクリプトの視覚的表現にします。これは一定のプロセスです。なぜなら、コンピュータにプロセッサがあり、システム上で一定の処理アクションが発生するからです。静的なものはなく、プロセスは状況に関係なく常に実行されています。

コンパイラ
は通常、コードを定義済みのバイトコード システムまたはマシン コード言語にコンパイルします。これは、コードの静的バージョンです。ソース コードが再コンパイルされない限り、マシンによって再解釈されることはありません。これが、プログラマーがソースでデバッグして再コンパイルする必要があるコンパイル後に実行時エラーが表示される理由です。インタープリターが意図するスクリプト (Javascript や PHP など) は、実行前にコンパイルされない単純な命令であるため、コンパイルはリアルタイムで行われるため、追加のコンパイル手順を必要とせずにソース コードを簡単に編集および修正できます。

すべてのコンパイル済みコードが同じように作成されるわけではない
これを簡単に説明する方法として、ビデオ ゲーム システムがあります。プレイステーション対Xbox。Xbox システムは、コーディングと開発を最適化するために .net フレームワークをサポートするように構築されています。C# は、コードをバイトコードにコンパイルするために、このフレームワークを共通言語ランタイムと組み合わせて利用します。バイトコードはコンパイルされたコードの厳密な定義ではありません。プログラムのコードをより迅速かつ大規模に記述できるようにするプロセスに配置される中間ステップであり、実行時にコードが実行されるときに解釈されます。ジャストインタイム JIT )。違いは、このコードは 1 回だけ解釈されることです。一度コンパイルすると、プログラムは再起動しない限りそのコードを再解釈しません。

解釈されたスクリプト言語はコードをコンパイルしないため、解釈されたスクリプトの関数は常に再処理されますが、コンパイルされたバイトコードの関数は一度解釈され、命令はプログラムのランタイムが停止するまで保存されます。利点は、必要なリソースが整っていれば、バイトコードを別のマシンのアーキテクチャに移植できることです。これが、プログラムが正しく機能するために、システムに .net と、場合によっては更新プログラムとフレームワークをインストールする必要がある理由です。

プレイステーションは、そのマシンに .net フレームワークを使用しません。C++ でコーディングする必要があります。C++ は、特定のシステム アーキテクチャ用にコンパイルおよびアセンブルするためのものです。コードが解釈されることはなく、実行するには正確である必要があります。中間言語のように、この型言語を簡単に移行することはできません。そのマシンのアーキテクチャ用に特別に作成されており、他の方法で解釈されることはありません。

したがって、コンパイルされた言語でさえ、コンパイルされた言語の本質的に最終化されたバージョンではないことがわかります。コンパイル済み言語は、その厳密な定義では、使用するために完全にコンパイルされることを意味します。解釈された言語は、プログラムによって解釈されることを意図していますが、スクリプトを理解するプログラムをインストールするだけでよいため、プログラミングで最も移植性の高い言語でもありますが、常に解釈されるため、ほとんどのリソースも使用します。中間言語 (Java や C# など) は、これら 2 つのハイブリッドであり、部分的にコンパイルしますが、機能を維持するために外部リソースも必要とします。実行すると、再度コンパイルされます。これは、実行時に一度だけ解釈されます。

プログラミングの進化

マシン コード
コーディングの最も低い形式であるこのコードは、その表現が厳密に 2 進数です (この議論では理論と実際の応用に基づいているため、3 進数の計算には触れません)。コンピュータは、オン/オフの真/偽という自然値を理解します。これはマシン レベルの数値コードであり、次のレベルのアセンブリ コードとは異なります。

アセンブリ コード
次のレベルのコードはアセンブリ言語です。これは、言語が機械によって使用されるように解釈される最初のポイントです。このコードは、マシン レベル コードでマシンに送信されるニーモニック、シンボル、およびオペランドを解釈するためのものです。これを理解することは重要です。なぜなら、プログラミングを初めて始めるとき、ほとんどの人は、コンパイルするか解釈するかのどちらかだと思い込んでしまうからです。低レベルの機械語コードを超えるコーディング言語は、命令のみをコンパイルするか、命令のみを解釈するものではありません!!!

これについては、「すべてのコンパイル済みコードが等しく作成されるわけではない」で説明しました。アセンブリ言語はこれの最初のインスタンスです。マシンコードは機械が読むものですが、アセンブリ言語は人間が読むことができるものです。コンピューターの処理速度が向上し、技術の進歩が進むにつれて、低レベル言語は本質的により凝縮され始め、手動で実装する必要がなくなります。アセンブリ言語は、マシンをコーディングするためのより迅速な方法であったため、高レベルのコーディング言語でした。それは本質的に、一度アセンブルされた (コンパイルの最も低い形式) 直接機械語に変換された構文言語でした。アセンブラはコンパイラですが、すべてのコンパイラがアセンブラというわけではありません。

ハイレベルコーディング
高レベルのコーディング言語は、アセンブリよりも 1 ステップ上の言語ですが、さらに高いレベルを含む場合もあります (これはバイトコード/中間言語になります)。これらの言語は、定義された構文構造から、必要なマシン コード、解釈されるバイトコード、またはアセンブリをインラインで記述できる特別なコンパイラと組み合わされた前の方法のいずれかのハイブリッドのいずれかにコンパイルされます。その前身である Assembly のような高レベルのコーディングは、開発者の作業負荷を軽減し、実行可能プログラムのビルドなどの冗長なタスクで重大なエラーが発生する可能性を排除することを目的としています。今日の世界では、開発者がサイズだけのためにデータを処理するためにアセンブリで作業することはめったにありません。ビデオ ゲーム コンソールの開発のように、開発者が状況に直面することはよくありますが、プロセスのスピードアップが必要な場合。高レベル コーディング コンパイラは、開発プロセスを容易にするためのツールであるため、そのシステム アーキテクチャで最も効率的な方法でコードを 100% コンパイルするとは限りません。その場合、システムのリソースを最大化するためにアセンブリ コードが記述されます。しかし、変人に会わない限り、機械語で書いている人を見ることはありません。

サマリー

ここまで来たら、おめでとうございます!あなたは、私の妻がこのことについて生涯にわたってできるよりも、一度に多くのことを聞いただけです。OP の質問は、while と for ループのパフォーマンスに関するものでした。これが今日の基準で議論の余地がある理由は 2 つあります。

理由 1
Javascript を解釈する時代は終わりました。すべての主要なブラウザー (はい、Opera や Netscape も) は、スクリプトを実装する前にコンパイルするように作成された Javascript エンジンを利用します。非呼び出しメソッドに関して JS 開発者によって議論されているパフォーマンスの微調整は、言語内のネイティブ関数を見ると時代遅れの研究方法です。コードは、DOM の一部になる前に、そのためにコンパイルおよび最適化されています。そのページはランタイム環境であるため、そのページがアップしている間は再度解釈されません。Javascript は、インタープリタード スクリプトというよりも、実際には中間言語になりました。それが中間スクリプト言語と呼ばれない理由は、Javascript がコンパイルされないためです。それが唯一の理由です。それ以外は」

理由 2 Web サイトのデスクトップ アプリケーションと同じくらいの処理能力を必要とするスクリプトまたはスクリプトのライブラリを作成する可能性はほとんどありません。なんで?Javascript は、包括的な言語になることを意図して作成されたことがないためです。その作成は、HTML や CSS では提供されないプロセスを実行できる中レベル言語プログラミング方法を提供するだけでなく、専用の高レベル コーディング言語、特に Java を必要とする開発の苦労を軽減することでした。

CSS と JS は、初期の Web 開発のほとんどでサポートされていませんでした。1997 年頃まで、CSS は安全な統合ではなく、JS はさらに長く戦っていました。Web の世界では、HTML 以外のすべてが補助言語です。

HTML は、サイトの構成要素として固有のものです。Web サイトを完全に構成するために JavaScript を記述することはありません。せいぜい DOM 操作を行いますが、サイトを構築します。

実用的ではないため、JS でサイトのスタイルを設定することはありません。CSS がそのプロセスを処理します。

Javascriptを使用して、一時的に保存する以外は決して保存しません。データベースを使用します。

それで、私たちは何を残しますか?ますます単なる機能とプロセス。CSS3 とその将来のイテレーションは、Javascript からスタイリングのすべてのメソッドを取得する予定です。アニメーションと疑似状態 (ホバー、アクティブなど) で既にそれがわかります。

この時点で Javascript のコードの最適化に関する唯一の有効な議論は、ユーザーの数式/コード パターンの最適化によって助けられる可能性のある、不適切に記述された関数、メソッド、および操作に対するものです。適切で効率的なコーディング パターンを学習している限り、今日の時代の Javascript は、ネイティブ関数のパフォーマンスを損なうことはありません。

于 2015-04-13T14:38:15.070 に答える