Frage Warum setzt setTimeout meine Schleife nicht ab?


Ich habe mich gefragt, wie oft ein JavaScript kann while Statement (in der Chrome-Konsole) kann eine Variable in einer Millisekunde inkrementieren, also habe ich dieses Snippet schnell direkt in die Konsole geschrieben:

var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }

Das Problem ist, dass es für immer läuft.
Warum passiert das und wie kann ich es lösen?


75
2018-02-09 08:04


Ursprung


Antworten:


Dies kommt auf die Ein-Thread-Natur von JavaScript zurück1. Was passiert, ist so ziemlich das:

  1. Ihre Variablen sind zugewiesen.
  2. Sie planen eine Funktion, um festzulegen run = false. Dies soll ausgeführt werden nach Die aktuelle Funktion wird ausgeführt (oder was auch immer gerade aktiv ist).
  3. Sie haben Ihre Endlosschleife und bleiben innerhalb der aktuellen Funktion.
  4. Nach Ihrer Endlosschleife (noch nie), das setTimeout() Callback wird ausgeführt und run=false.

Wie Sie sehen können, a setTimeout() Ansatz wird hier nicht funktionieren. Sie könnten das umgehen, indem Sie die Zeit in der while Bedingung, aber dies wird Ihre tatsächliche Messung manipulieren.

1 Zumindest für mehr praktische Zwecke können Sie es als single-threaded sehen. Eigentlich gibt es eine sogenannte "Event-Schleife". In dieser Schleife werden alle Funktionen in die Warteschlange gestellt, bis sie ausgeführt werden. Wenn Sie eine neue Funktion in eine Warteschlange stellen, wird sie an die entsprechende Position innerhalb dieser Warteschlange gesetzt. Nach Ist die aktuelle Funktion beendet, übernimmt die Maschine die nächste Funktion aus der Warteschlange (in Bezug auf Zeitvorgaben, wie sie z setTimeout() und führt es aus.
Als Ergebnis wird zu jedem Zeitpunkt nur eine Funktion ausgeführt, wodurch die Ausführung ziemlich einfach wird. Es gibt einige Ausnahmen für Ereignisse, die im folgenden Link erläutert werden.


Als Referenz:


81
2018-02-09 08:10



JavaScript ist single-threaded, also während Sie in der Schleife sind, wird nichts anderes ausgeführt.


24
2018-02-09 08:11



Um die tatsächliche Geschwindigkeit von Chrome beizubehalten, ohne ständig die Zeit zur Berechnung der Geschwindigkeit abrufen zu müssen, können Sie diesen JS-Code ausprobieren:

var start = new Date().getTime()
var i = 0
while(i<1000000)
{
    i++
}
var end = new Date().getTime()
var delta = end-start
var speed = i/delta
console.log(speed + " loops per millisecond")

19
2018-02-09 13:29



Javascript ist single-threaded, das bedeutet, dass es nacheinander nur eine Anweisung ausführt.

Das Ereignissystem wird, wie in vielen anderen Sprachen und Bibliotheken, von einer Ereignisschleife gehandhabt. Die Ereignisschleife ist im Grunde eine Schleife, die bei jeder Iteration nach einer Nachricht in der Warteschlange sucht und Ereignisse absendet.

In Javascript (wie in mot von Sprachen, die dieses Muster implementieren) wird die Ereignisschleife aufgerufen, wenn der Stapel leer ist, dh wenn alle Funktionen zurückgegeben werden, mit anderen Worten, am Ende des Programmcodes.

Ihr "echtes" Programm sieht in etwa so aus:

var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }

while(true) {
/*
 * check for new messages in the queue and dispatch
 * events if there are some
 */
  processEvents();
}

Die Nachricht von der Uhr, dass das Timeout abgelaufen ist, wird also nie verarbeitet.

Weitere Informationen zur Ereignisschleife finden Sie unter: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop


Natürlich ist es etwas komplizierter, schaue hier die Beispiele: Ist JavaScript garantiert single-threaded? (tl; dr: In einigen Browser-Engines sind einige externe Ereignisse nicht von der Ereignisschleife abhängig und werden sofort ausgelöst, wenn sie auftreten, wodurch die aktuelle Aufgabe vorweggenommen wird. Dies ist jedoch bei setTimeout nicht der Fall, da nur eine Nachricht zur Warteschlange hinzugefügt und nicht sofort ausgelöst wird.


4
2018-02-09 15:16



Die While-Schleife greift nicht auf setTimeout zu. Sie haben Code, der setzt, wahr, und dann wird es nie falsch werden.


2
2018-02-09 20:06



JavaScript hat einen einzelnen Thread und hat single-threaded überall.

Ich denke diese Frage ist gut: Ist JavaScript garantiert single-threaded?

Wenn Ihr Code in einer Schleife ist, werden andere Ocde nicht ausgeführt und blockiert.


1
2018-02-10 04:31