2015-07-08 15 views
7

Ich habe mit Skripten arbeiten mit SetInterval (Fn, Verzögerung) -Funktion in meiner Anwendung und nachdem ich gelesen habe, wie SetTimeout und JS arbeiten ich einige seltsame Ergebnisse, so dass ich einen Test gemacht: Hier ist die jsfiddle https://jsfiddle.net/jyq46uu1/2/Javascript setTimeout unerwartete Ausgabe

Und wie der Code vorgeschlagen:

var limit  = 1000000000; 
var intervals = 0; 
var totalTime = new Date(); 
var startTime = new Date(); 

var uid = setInterval(
    function() { 
     // final lap? 
     if (intervals == 9) clearInterval(uid); 

     for (i = 0; i < limit; i += 1) { 
      // just working the CPU 
     } 
     // reduce the iterations 
     limit = limit/10; 
     intervals += 1;   

     console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime)); 
     // reset the time 
     startTime = new Date(); 
    }, 250, 9); 

Ok, was ich red von http://ejohn.org/blog/how-javascript-timers-work/ Javascript haben die Timer-Anrufe für die Funktion in setInterval selbst machen, wenn der "Thread blockiert", so Wenn die Funktion noch ausgeführt wird, wird der Anruf gerade in die Warteschlange gestellt und so weiter ... in meinem Notebook produziert, dass Code aus:

"Interval 1 Time elapsed : 4264" 
"Interval 2 Time elapsed : 477" 
"Interval 3 Time elapsed : 91" 
"Interval 4 Time elapsed : 170" 
"Interval 5 Time elapsed : 246" 
"Interval 6 Time elapsed : 242" 
"Interval 7 Time elapsed : 248" 
"Interval 8 Time elapsed : 248" 
"Interval 9 Time elapsed : 248" 

Ok, wenn das, was ich rot habe wahr ist, durch die Zeit, das erste Intervall beendet ist, wurden alle Funktionen Anrufe in der Warteschlange ... in meinem Skript Ich reduziere die Arbeit für jede Ausführung, so dass jeder Anruf weniger Sekunden dauern sollte als der vorherige, ABER egal wie viele Iterationen ich einstelle, die verstrichene Zeit nimmt immer das Intervall-Tempo nach dem vierten Lauf auf. Vielleicht habe ich es falsch verstanden, aber wenn zur Zeit 4264 alle Funktionen bereits in der Warteschlange sind und sofort ausgeführt werden sollen, sollten sie weniger Zeit zeigen, oder? ... wenn die dritte Iteration 91 anzeigt und die anderen knapp dahinter stehen, sollten sie 91 oder weniger nehmen. Aber das ist nicht der Fall.

Wenn Sie verstehen, was passiert, bitte erklären Sie es mir, weil ich denke, dass ich etwas vermisse.

Antwort

1

Ich denke, das erste Mal zählt nicht aus dem ersten Intervall in der Warteschlange, sondern von dem Punkt, an dem Sie StartTime festlegen.

Dann zählt der erste Timer Initialisierungszeit, Umgebungserstellung, Variablen und Timerzuordnung.

Versuchen Sie, diese Änderung:

var limit  = 1000000000; 
var intervals = 0; 
var totalTime = new Date(); 
var startTime = false; 

var uid = setInterval(
    function() { 
     if (!startTime) startTime = new Date(); 
     // final lap? 
     if (intervals == 9) clearInterval(uid); 

     for (i = 0; i < limit; i += 1) { 
      // just working the CPU 
     } 
     // reduce the iterations 
     limit = limit/10; 
     intervals += 1;   

     console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime)); 
     // reset the time 
     startTime = new Date(); 
    }, 250, 9); 

Auch das erste Mal länger wahrscheinlich dauert, weil die Funktion interpretiert wird, dann werden die nachfolgenden Zeiten „kompiliert“/optimiert durch die Javascript JIT (siehe https://en.wikipedia.org/wiki/Just-in-time_compilation) ausgeführt wird . Überprüfen Sie den Code aus den Beweis zu sehen

var limit  = 1000000000; 
var intervals = 0; 
var totalTime = new Date(); 
var startTime = new Date(); 

var uid = setInterval(
    function() { 
     startTime = new Date(); 
     // final lap? 
     if (intervals == 9) clearInterval(uid); 

     for (i = 0; i < limit; i += 1) { 
      // just working the CPU 
     } 
     // reduce the iterations 
     limit = limit/10; 
     intervals += 1;   

     console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime)); 
     // reset the time 
     startTime = new Date(); 
    }, 250, 9); 

die Ausgabe:

Interval 1 Time elapsed : 3249 
Interval 2 Time elapsed : 299 
Interval 3 Time elapsed : 31 
Interval 4 Time elapsed : 5 
Interval 5 Time elapsed : 0 
Interval 6 Time elapsed : 0 
Interval 7 Time elapsed : 0 
Interval 8 Time elapsed : 0 
Interval 9 Time elapsed : 0 
Interval 10 Time elapsed : 0 

setInterval nicht gut ist, die Zeit zu messen, in dem sollte es die nächste Ausführung Warteschlange. Ich denke, das hat mit Schlaf zu tun. Es ist nicht zuverlässig, wenn ein Prozess die CPU nimmt und hängt (wie für Sie).

setInterval garantiert nur das:

  • Execution Nummer 1 wird nicht in weniger als 250 ms passieren.
  • Ausführung Nummer 2 wird nicht in weniger als 2 * 250ms vorausgehen.
  • Ausführung Nummer 3 wird nicht in weniger als 3 * 250ms vorausgehen.
  • ...

setInterval garantiert nicht, dass einige Ausführung vor einem bestimmten Zeitpunkt in der Zukunft passieren wird. Das hängt von der aktuellen CPU-Auslastung ab.

Das Einreihen und Starten von Warteschlangenfunktionen hängt auch von der aktuellen CPU-Auslastung ab.

Zusätzliche Allgemeine Tipps Wenn Sie eine Funktion in regelmäßigen Abständen ausführen müssen, ich diesen Ansatz empfehlen, die etwa zwischen Ausführungen

var t = false; 
var fun = function() { 
    console.log("run"); 
    t = setTimeout(fun, 250); 
} 
fun(); 
+0

Ich bin fasziniert über den zweiten Code ... Ich sehe nicht den Unterschied von der ersten, aber die Ausgabe ist eindeutig anders –

+0

@GabrielMatusevich 'startTime = new Date();' an der Spitze der Funktion – Andreas

+0

Ich habe 'startTime = new Date(); 'als erste Zeile in Funktion, um die verstrichene Zeit NUR für die Funktion zu sehen, ohne Nebenwirkungen in der Zeitmessung von setinterval – jperelli

0

Ich bin mir nicht sicher, ob ich recht habe und auf was ich von "Javascript" weiß.

Javascript basiert auf ereignisbasierter Triggerung und es gibt "keine Warteschlange und warten". Es wird einfach gleichzeitig gehen (so etwas wie Threading).

Ich denke, das wird Sinn machen, wie schnell es interpretieren und den nächsten aufnehmen.

+3

JavaScript ist single-threaded ... –

+0

überhaupt nicht @Alexander, lesen Sie bitte hier. http://stackoverflow.com/questions/2734025/is-javascript-guaranteed-to-be-single-hreaded –

+1

Lesen Sie die am höchsten bewerteten Kommentare zu dieser Antwort. Ein solches Verhalten macht JavaScript nicht multi-threaded. Das ist das Verhalten des Hosts, wenn das Skript die Umgebungs-APIs aufruft, die mehr von Ihrem Code aufrufen können, bevor Sie zu dem Code zurückkehren, der die API aufgerufen hat. Keine zwei Abschnitte Ihres Codes werden jemals gleichzeitig ausgeführt (ohne einen Worker). –

0

Nun, ich habe einige Punkte eine Verzögerung immer greather als 250 ms garantiert zu sprechen, sehen die Ergebnisse zuerst.

Results Image

Der „neue“ Code:

var limit  = 1000000000; 
var intervals = 0; 
var totalTime = new Date(); 

top.uid = setInterval(
    function() { 
     startTime = new Date(); 
     // final lap? 
     if (intervals == 9) clearInterval(top.uid); 

     for (i = 0; i < limit; i += 1) { 
      // just working the CPU 
     } 
     // reduce the iterations 
     limit = limit/10; 
     intervals += 1; 

     console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime)); 
     // reset the time 
    }, 1); 

beachte, dass ich die variable Startzeit aus der Leitung 4 entfernen und es zu Beginn der Funktion übergeben, so wird die berechnete Zeit ist die gleiche für alle Anrufe. Ich habe das TIMER-Formular von 250 ms auf 1 ms geändert, sodass Sie für jedes Ergebnis keine -250 ms berechnen müssen.

Die neuen Ergebnisse sind ziemlich konsistent und zeigen, dass die Zeit für die Berechnung sehr akzeptabel und kohärent ist.

Ich hoffe, ich half, es aufzuräumen.