2015-01-06 7 views
5

Ich habe eine Anwendung, die ich viel Werte Array drücken, so dass ich testen Sie die Ausführungszeit:SetTimeout in Javascript-Schliesser schneller laufen

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); 

ich die Codes in Firefox-Konsole und Chrome-Konsole laufen direkt und es kostet 37 seconds. Und während der Ausführung kann sogar die Maus in Chrome bewegt werden, aber es gibt keinen interaktiven Effekt.

Dann habe ich die Codes ändern:

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); 

Vereinfachen Sie die Codes in Funktion setzen, und nennen es die setTimeout verwenden, kostet es 0.844 second. Und während der Ausführung kann ich normalerweise in Chrome arbeiten.

Screenshot of console

Was ist hier los?

Ich weiß, dass die setTimeout die Steuerung an den Browser setzen wird, um den UI-Job zu machen, der die Seite reagieren lässt. Wenn ich zum Beispiel während der Mausbewegung der Seite eine Berechnung durchführe, würde ich die Berechnung verzögernd ausführen, um zu verhindern, dass sie die Benutzeroberfläche blockiert.

Aber warum reduzieren Sie die gesamte Ausführungszeit der gleichen Codes?

+1

Vielleicht ist es nur Caching. Haben Sie versucht, die Ausführungsreihenfolge zu vertauschen, d. H. Zuerst die setTimeout-Variante und dann die andere? –

+0

Was passiert, wenn Sie einfach 'push()' aufrufen? – Freez

+0

Es dauert die gleiche Zeit mit oder ohne Zeitüberschreitung für mich. – DoctorMick

Antwort

5

Und während der Ausführung kann ich in Chrome normal arbeiten.

Nicht wahr. Das Hauptfenster ist genauso tief gefroren wie das andere (nur für kurze Zeit). Die Debug-Tools sind ein separater Thread und werden nicht langsamer.

Aber warum es die Gesamtausführungszeit des gleichen Codes reduzieren?

Es funktioniert, wenn Sie in Dev-Tools ausgeführt werden. Wenn Sie den Code in Wirklichkeit ausführen, wo die VM Eigenschaften optimieren kann, sind die Zeiten vergleichbar (fast 1 Sekunde). z.B.

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/ Sie werden sehen, die normal führt genauso schnell wie setTimeout.

Auch wenn Sie den Code in einer Funktion, und führen Sie in einer Konsole wickeln wird die Zeit vergleichbar sein, auch ohne setTimeout als die VM Optimierungen zwischen Funktionsdefinition und Ausführung machen können:

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

Ihre Geige benutzt 'onload', was die Ausführung des Codes geändert hat. –

+0

@SalmanA du hattest Recht. Ich habe die Geige gewechselt, um roh zu spielen, und die Ergebnisse sind immer noch vergleichbar. – basarat

1

Alle JavaScript-Engine durchführen verschiedene Optimierungen. Zum Beispiel verwendet V8 2 Compiler, einen einfachen standardmäßig und einen optimierenden. Der vom optimierenden Compiler kompilierte Code ist langsam, sehr langsam.

Eine Bedingung für die Ausführung des optimierenden Compilers ist, dass der Code in einer (nicht zu langen) Funktion (there are other conditions) vorliegen muss. Der erste Code, den Sie in der Konsole ausprobiert haben, ist nicht in einer Funktion. Setzen Sie Ihren ersten Code in eine Funktion und Sie werden sehen, dass es genauso funktioniert wie die zweite, setTimeout ändert nichts.

Es macht keinen Sinn, nach Leistungen in der Konsole zu suchen, wenn der Hauptleistungsfaktor die optimierende Zusammenstellung ist. Wenn Sie auf einen Knoten ausgerichtet sind, verwenden Sie ein Benchmarking-Framework. Wenn Sie auf den Browser zielen, verwenden Sie eine Website wie jsperf.

Jetzt, wenn Sie eine wirklich lange Berechnung im Browser durchführen müssen (was hier nicht der Fall zu sein scheint), sollten Sie using web workers in Betracht ziehen, die den Job in einem Hintergrundthread nicht die Benutzeroberfläche beeinträchtigen.

+0

Wie wäre es, wenn ich eine lange Berechnung in Nodewebkit ausführen müsste? Ich frage mich nur, ob das Erstellen eines Arrays mit Millionen von Elementen die Benutzeroberfläche blockieren wird? Deshalb teste ich die Funktion. – hguser

2

Beide Code-Varianten sollten mit fast identischer Geschwindigkeit ausgeführt werden (das letzte Beispiel ist möglicherweise schneller, aber nicht 10-mal schneller).

In den Chrome-Entwicklertools gibt es eine andere Geschichte. Die Ausdrücke werden innerhalb eines with Blocks ausgewertet. Das bedeutet, dass die Variablen wie a und i zuerst in einem anderen Objekt (__commandLineAPI) gesucht werden. Dies fügt einen zusätzlichen Overhead hinzu, der zu einer 10 mal längeren Ausführungszeit führt.

+0

Das ist nicht wirklich der Grund. Die Funktion (Ihr IIFE) ist der Grund. –

+0

Der Punkt ist, dass Sie in diesem Beispiel innerhalb einer lokalen Variablen "a" statt "window.a" drücken. –

+0

Ja, aber das wirkt sich nicht so sehr auf die Leistung aus als den Code in eine Funktion zu setzen (versuchen Sie es mit 'window.a') –

0

setTimeout, wie andere bemerkt, beschleunigt nicht die Array-Erstellung und macht den Browser sperren. Wenn Sie Bedenken hinsichtlich der Browsersperre während der Array-Erstellung haben, können Web-Worker (siehe MDN) zur Rettung kommen. Hier ist eine jsFiddle Demo mit einem Web-Arbeiter für Ihren Code. Der Worker-Code ist in der 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] + ']'}); 
} 
Verwandte Themen