Things (ich glaube) verstehenReihenfolge der Ereignisse in JS Ereigniswarteschlange
Trotz der Tatsache, dass moderne Browser Multi-Threaded sind, ist JavaScript Single-Thread ausgeführt und es wird garantiert synchron ausgeführt werden. Das heißt, wenn der Aufrufstapel eingegeben wird, läuft der JS ununterbrochen, bis der Aufrufstapel wieder leer wird. Insbesondere ist sichergestellt, dass keine zwei JS-Skripte gleichzeitig ausgeführt werden.
JavaScript ist jedoch ereignisgesteuert. Gemäß der description of the concurrency model at MDN führt der Browser eine Warteschlange von Ereignissen. Im Leerlauf nimmt der Browser das erste Ereignis aus der Warteschlange und führt das zugehörige JS-Objekt (falls vorhanden) aus. Nachdem das Skript beendet wurde, erlangt der Browser wieder die Kontrolle und fährt mit dem nächsten Ereignis fort. Während ein JS-Skript ausgeführt wird, macht der Browser nichts anderes, insbesondere blockiert es die Benutzeroberfläche. Letzterer ist verantwortlich für die berüchtigte "langlaufende Skript-Warnung".
Es gibt einige wirklich asynchrone Funktionen wie setTimeout
, die vom Laufzeitsystem (auch bekannt als Browser) zur Verfügung gestellt werden. Sie können verwendet werden, um ein neues Ereignis in die Ereigniswarteschlange einzufügen, und der zugehörige Rückruf wird auf den Aufrufstapel gesetzt, wenn das Ereignis ausgelöst wurde und der Aufrufstapel leer ist. Ein Entwickler kann seine "eigenen" asynchronen Funktionen nicht erstellen, ohne eine der nativen asynchronen Funktionen zu verwenden.
Dies gesagt, setTimeout(someFunction, 0)
bietet eine Option zum Aufteilen eines lang laufenden Stück Code, die sonst die "lang laufende Skript Warnung" in kleinere Stücke auslösen würde. Wenn der Aufruf-Stack leer wird, kann der Browser andere Ereignisse (wie die Benutzeroberfläche) einholen, bevor er das nächste Stück Code ausführt.
Ein Beispiel
Um zu überprüfen, ob ich recht habe ich erstellt dieses piece of code
"use strict";
for(var i = 0; i != 5; i++) {
confirm('This is #: ' + i);
setTimeout(
(function(j) {
return function() { confirm('This is #: ' + j); };
})(i+10),
0
);
}
Erwartete Ergebnisse
ich die Alertbox erwartet in der richtigen Reihenfolge zu kommen: 0 , 1, 2, 3, 4, 10, 11, 12, 13 und 14. Meine Idee war, dass bei jeder Iteration die folgenden zwei Schritte passieren: (a) Die erste Bestätigungsbox wird syn angezeigt chronisch. (b) Ein neues Ereignis wird an das Ende der Ereigniswarteschlange gesendet. Der Callback wird jedoch noch nicht aufgerufen, sondern zurückgestellt, da der Aufruf-Stack nicht leer ist, da die Schleife noch läuft.
Daher erwartete ich, die Warnungen 0, 1, 2, 3, 4 zuerst in dieser Reihenfolge zu sehen, weil dies Teil der synchronen Schleife ist. Dann endet die Schleife und der Aufrufstapel wird klar. Das nächste Ereignis wird aus der Ereigniswarteschlange genommen, bei der es sich um das erste asynchrone Zeitlimit handelt. Also erwartete ich, 10 als nächstes zu sehen. Nach dem Schließen des Bestätigungsdialogs wird der Call Stack wieder gelöscht. Also habe ich erwartet, 11 als nächstes zu sehen. Und so weiter.
Die tatsächlichen Ergebnisse
Die Alarmboxen werden in gemischter Reihenfolge gezeigt, z.B. 0, 1, 2, 10, 11, 3, 12, 4, 13, 14
Frage
Warum sind die Alertbox in gemischter Reihenfolge? Wenn mindestens der synchrone Teil (0, 1, 2, 3, 4) im Block angezeigt wurde und nur die Rückrufe vertauscht waren, hätte ich akzeptiert, dass die Ereigniswarteschlange keine Reihenfolge des Ereignisses garantiert.Es scheint jedoch, dass sogar die synchrone Schleife unterbrochen und mit den asynchronen Ereignissen verschachtelt wird. Ich dachte, das wird garantiert nicht passieren. Was geht hier vor sich?
Welchen Browser testen Sie? Wenn ich deine Geige in Chrome laufe, scheint es durchgängig (ich habe es etwa zehnmal probiert) zuerst 0, 1, 2, 3, 4 zu zeigen, aber dann ändert sich die Reihenfolge der> = 10 Eingabeaufforderungen. (Beachten Sie, dass Sie, wenn Sie 'console.log()' anstelle von 'confirm()' verwenden, die erwartete Reihenfolge erhalten.) – nnnnnn
Ich bin momentan nicht in der Lage dies zu testen, aber in Einige Browser (Firefox sowieso), die Funktionen wie "alert" und "confirm" blockieren, sind semi-asynchron (die Benutzeroberfläche wird nicht blockiert und einige Ereignisse werden ausgelöst). Vielleicht ist das der Grund? –
Werfen Sie einen Blick auf diese aktualisierte Geige: https://jsfiddle.net/5kzv973x/4/ - der Browser nutzt die Gelegenheit, den Bildschirm neu zu streichen, während Sie darauf warten, dass Sie die 'confirm()' schließen. – nnnnnn