2015-01-06 12 views
5

私は配列に多くの値をプッシュする必要がアプリケーションを持っているので、私は、実行時間をテスト:のsetTimeout速く

var st = new Date().getTime(); 
var a = []; 
for (var i = 0; i < 20971520; i++) { 
    a.push(i); 
} 
var ed = new Date().getTime(); 
console.info((ed - st)/1000); 
console.info(a.length); 

私は直接FirefoxのコンソールとChromeコンソールでコードを実行しますそれは37 secondsです。実行中はマウスでさえもChromeで移動できますが、インタラクティブな効果はありません。

その後、私はコードを変更:

function push() { 
    var st = new Date().getTime(); 
    var a = []; 
    for (var i = 0; i < 20971520; i++) { 
    a.push(i); 
    } 
    var ed = new Date().getTime(); 
    console.info((ed - st)/1000); 
    console.info(a.length); 
} 

var tr = setTimeout(push, 50); 

簡素化は、それが0.844 secondの費用がかかり、関数内のコードを入れて、setTimeoutを使用してそれを呼び出します。そして実行中に、私はChromeで正常に操作できます。

Screenshot of console

ここで何が起こっているの?

私はsetTimeoutがブラウザにUIジョブを実行するためのコントロールを置くことを知っています。これによりページが応答しやすくなります。たとえば、私はページのmousemove中にいくつかの計算を行うとき、私はそれがUIをブロックしないように遅延実行された計算を入れます。

しかし、なぜ同じコードの実行時間が短縮されるのでしょうか?

+1

多分それはちょうどキャッシングです。実行順序を入れ替えようとしましたか?つまり、最初にsetTimeoutバリアントを実行してから、もう一方を実行しましたか? –

+0

'push()'を呼び出すとどうなりますか? – Freez

+0

タイムアウトの有無にかかわらず同じ時間がかかります。 – DoctorMick

答えて

5

実行中、Chromeで正常に操作できます。

メインのクロムウィンドウは、他のケースとちょうど同じくらい凍結されます。デバッグツールは別のスレッドであり、速度は落ちません。

しかし、なぜ同じコードの実行時間が短縮されるのでしょうか?

開発ツールで実行するとします。 VMがプロパティの最適化を行うことができる実際にコードを実行すると、時間は同等です(ほぼ1秒)。例えば

var st = new Date().getTime(); 
    var a = []; 
    for (var i = 0; i < 20971520; i++) { 
     a.push(i); 
    } 
    var ed = new Date().getTime(); 
    console.info('normal', (ed - st)/1000); 
    console.info(a.length); 

    function push() { 
     var st = new Date().getTime(); 
     var a = []; 
     for (var i = 0; i < 20971520; i++) { 
      a.push(i); 
     } 
     var ed = new Date().getTime(); 
     console.info('timeout', (ed - st)/1000); 
     console.info(a.length); 
    } 

    var tr = setTimeout(push, 0); 

http://jsfiddle.net/gu9Lg52j/あなたはnormalsetTimeoutと同じくらい速いを実行表示されます。

function push() { 
     var st = new Date().getTime(); 
     var a = []; 
     for (var i = 0; i < 20971520; i++) { 
      a.push(i); 
     } 
     var ed = new Date().getTime(); 
     console.info('timeout', (ed - st)/1000); 
     console.info(a.length); 
    } 
    push(); 
+0

あなたのフィドルは 'onload'を使ってコードの実行方法を変更しました。 –

+0

@サルマンあなたは正しいです。私は生の実行のためにフィドルを変更し、結果はまだ同等です。 – basarat

1

すべてのJavaScriptエンジンで実行:あなたは関数内のコードをラップし、コンソールで実行した場合、VMは、関数の定義と実行の間の最適化を行うことができますよう

また時間がさえsetTimeoutせずに匹敵しますさまざまな最適化。たとえば、V8では2つのコンパイラが使用されます。コンパイラはデフォルトで使用される単純なものと最適化されたものです。最適化コンパイラによってコンパイルされないコードは遅い、非常に遅いです。

最適化コンパイラを実行する条件は、コードが長すぎない関数(there are other conditions)でなければならないという条件です。コンソールで試した最初のコードは関数ではありません。あなたの最初のコードを関数に入れると、それは2番目のコードと同じコードを実行することがわかります。setTimeoutは何も変わりません。

主なパフォーマンス要因が最適化コンパイルの場合、コンソールでのパフォーマンスをチェックするのは無意味です。ノードをターゲットにしている場合は、ベンチマークフレームワークを使用します。ブラウザをターゲットにしている場合は、jsperfのようなサイトを使用します。

ブラウザで実際に長い計算をしなければならない場合(ここではそうではないようです)、バックグラウンドスレッドのジョブをUIに影響させないように、using web workersを考慮する必要があります。

+0

Nodewebkitで長い計算を実行する必要がある場合はどうでしょうか、実際には、何百万もの要素を持つ配列を作成するとUIがブロックされるのだろうか?だから私はその機能をテストしている。 – hguser

2

両方のコードをほぼ同じ速度で実行する必要があります(後者の例は高速ですが、10倍高速ではありません)。

Chromeデベロッパーツールの中には、別の話があります。式はwithブロック内で評価されます。つまり、aiなどの変数は、別のオブジェクト(__commandLineAPI)内で最初に検索されます。これにより、オーバーヘッドが追加され、実行時間が10倍長くなります。

+0

それは本当の理由ではありません。機能(あなたのIIFE)がその理由です。 –

+0

この例では、 'window.a'の代わりにローカル変数' a'を押し込んでいます。 –

+0

はい、それは関数にコードを入れるほどのパフォーマンスには影響しません( 'window.a'を試してみてください) –

0

setTimeoutは、他の人が気づいたように、アレイの作成を高速化しません。にブラウザをロックします。配列の作成中にブラウザのロックアップが心配な場合は、WebワーカーMDNを参照)が救助になるかもしれません。あなたのコードにウェブワーカーを使用しているjsFiddleデモがあります。ワーカーコードはhtml内にあります:

onmessage = function (e) { 
    var a = [], now = new Date; 
    for (var i=0; i<20971520; i++) { 
    a.push(i); 
    } 
    postMessage({timings: 'duration: '+(new Date()-now) + 
         'Ms, result: [' + a[0] + '...'+a[a.length-1] + ']'}); 
}