50

次のような4つの異なる関数を作成しました。

var normal = function() {
    return;
};
var control = function() {
    return;
    alert("Hello, world!");
};
var withArguments = function() {
    return;
    arguments;
};
var withEval = function() {
    return;
    eval("");
};

何もせずにすぐに戻ってくるので、同じ速度になると思います。しかし、jsPerfでテストした後、私はそれを見つけてほぼ同じように実行しますがnormal、実行速度ははるかに遅くなります。controlwithArgumentswithEval

これらの実行されていないステートメントがパフォーマンスに影響を与えるのはなぜですか?それらは決して実行されないので、どのようにそれらが効果を発揮することができるのでしょうか?

4

1 に答える 1

64

つまり、eval関数の内部を呼び出すことと配列にアクセスできることのarguments両方で、関数の呼び出し中に追加の設定が使用されます。どちらargumentseval実行されないことがわかっている場合は、この追加の設定をスキップできます。

コンパイラは、arguments配列が実際にアクセスされるかどうか、またはeval実際に呼び出されるかどうかを予測しようとはせず、それらが関数に存在するかどうかをチェックするだけです。

arguments

argumentsオブジェクトを使用しない「通常の」関数よりも、オブジェクトを使用する可変個引数関数を呼び出す方が、実行時にコストがかかりargumentsます。

argumentsオブジェクトが宣言されたときに実行環境をバインドするために必要な追加の手順は、ECMA-262標準の§10.6で指定されています。argumentsオブジェクトの作成は、ややコストのかかる15ステップのプロセスです。基本的にarguments、渡された引数を入力する必要があり、プロパティ.caller.calleeプロパティを作成する必要があります。

標準では、 。argumentsという名前の関数内に宣言されたパラメーター、変数、または関数が既に存在しない限り、関数が実行コンテキストに入るときにオブジェクトを作成する必要があるとされていますarguments

最適化の目的で、関数が実際にどこかで引数オブジェクトを使用しない限り、ほとんどのブラウザーは実際には引数オブジェクトを作成しません(return)の後でも。argumentsこれが、参照されると、それを含む行が実行されない場合でも、パフォーマンスが低下する理由です。

eval

ECMA-262標準の§10.4.2で指定されているevalようにコードを入力するには、特別な実行コンテキストを作成する必要があります。基本的に、呼び出し元の関数の実行コンテキストのすべてのプロパティをコンテキストにバインドする必要があります。eval

1つの関数で複数evalのが呼び出された場合、基本的に両方が同じプロセスを2回実行します。最適化のために、ブラウザがeval関数にが含まれていることを検出すると(の後でさえreturn)、すべてが使用できるこの新しい実行コンテキストを事前に入力evalするため、何度も再作成する必要はありません。


これらの最適化はブラウザに依存し、標準では必要とされないため、一部のブラウザは説明されている最適化を実際に実行しない場合や、動作が異なる場合があることに注意してください。

于 2012-09-12T15:15:08.727 に答える