Inhaltsverzeichnis- Vorwort
- Das Prinzip der asynchronen Browser-JS-Ausführung
- Die Ereignisschleife im Browser
- Ausführungsstapel und Aufgabenwarteschlange
- Makrotasks und Mikrotasks
- Asynchrone/wartende Ausführungsreihenfolge
- Merkmale
- Beispiel
- Persönliche Analyse
Vorwort
Die Kenntnis der Ereignisschleife und des Betriebsmechanismus des Browsers trägt wesentlich zum Verständnis des Ausführungsprozesses von JavaScript und der Behebung von Betriebsproblemen bei. Nachfolgend finden Sie eine Zusammenfassung einiger Prinzipien und Beispiele von Browser-Ereignisschleifen.
Das Prinzip der asynchronen Browser-JS-Ausführung
- JS ist Single-Threaded, was bedeutet, dass es immer nur eine Sache gleichzeitig tun kann. Warum können Browser also asynchrone Aufgaben gleichzeitig ausführen?
- Da der Browser über mehrere Threads verfügt, startet der Browser einen anderen Thread, um die Aufgabe auszuführen, wenn JS eine asynchrone Aufgabe ausführen muss.
- Mit anderen Worten ist JS ein Single-Thread, was bedeutet, dass es nur einen Thread gibt, der JS-Code ausführt, nämlich den vom Browser bereitgestellten JS-Engine-Thread (Haupt-Thread). Es gibt auch Timer-Threads und HTTP-Anforderungs-Threads im Browser, die nicht hauptsächlich zum Ausführen von JS-Code verwendet werden.
- Wenn beispielsweise eine AJAX-Anforderung im Hauptthread gesendet werden muss, wird diese Aufgabe an einen anderen Browser-Thread (HTTP-Anforderungsthread) übergeben, um die Anforderung tatsächlich zu senden. Nachdem die Anforderung zurückgekommen ist, wird der im Rückruf auszuführende JS-Rückruf zur Ausführung an den JS-Engine-Thread übergeben.
- Das heißt, der Browser ist derjenige, der tatsächlich die Aufgabe des Sendens der Anforderung ausführt, und JS ist nur für die Ausführung der endgültigen Rückrufverarbeitung verantwortlich. Die Asynchronität wird hier also nicht von JS selbst implementiert, sondern ist tatsächlich eine vom Browser bereitgestellte Funktion.

Die Ereignisschleife im Browser
Ausführungsstapel und Aufgabenwarteschlange
Wenn JS einen Codeabschnitt analysiert, sortiert es den synchronen Code der Reihe nach an einer bestimmten Stelle, nämlich dem Ausführungsstapel , und führt dann die darin enthaltenen Funktionen nacheinander aus. Wenn eine asynchrone Aufgabe auftritt , wird sie zur Verarbeitung an andere Threads übergeben. Nachdem alle synchronen Codes im aktuellen Ausführungsstapel ausgeführt wurden, wird der Rückruf der abgeschlossenen asynchronen Aufgabe aus einer Warteschlange genommen und dem Ausführungsstapel hinzugefügt, um die Ausführung fortzusetzen. Wenn eine asynchrone Aufgabe auftritt, wird sie an andere Threads übergeben usw. Nachdem andere asynchrone Aufgaben abgeschlossen sind, wird der Rückruf zur Ausführung in die Aufgabenwarteschlange gestellt . 
Makrotasks und Mikrotasks
Je nach Aufgabentyp kann sie in eine Mikroaufgabenwarteschlange und eine Makroaufgabenwarteschlange unterteilt werden. Während der Ereignisschleife prüft der Ausführungsstapel nach der Ausführung des synchronen Codes zunächst, ob sich in der Mikrotask-Warteschlange eine auszuführende Aufgabe befindet. Wenn nicht, prüft er, ob sich in der Makrotask-Warteschlange eine auszuführende Aufgabe befindet, und so weiter. Mikrotasks werden im Allgemeinen zuerst in der aktuellen Schleife ausgeführt, während Makrotasks bis zur nächsten Schleife warten. Daher werden Mikrotasks im Allgemeinen vor Makrotasks ausgeführt, und es gibt nur eine Mikrotask-Warteschlange, obwohl es mehrere Makrotask-Warteschlangen geben kann. Darüber hinaus gehören auch allgemeine Ereignisse wie Klicks und Tastaturereignisse zu Makroaufgaben.
Allgemeine Makroaufgaben: - setTimeout()
- setInterval()
- UI-Interaktionsereignisse
- Nachricht
- setImmediate() – nodeJs
Häufige Mikroaufgaben: - versprechen.dann(), versprechen.fangen()
- neuer MutationObserver()
- process.nextTick() - nodeJs
Das folgende Beispiel:
console.log('Synchronisierter Code 1');
setzeTimeout(() => {
console.log('Zeitlimit festlegen')
}, 0)
neues Versprechen((lösen) => {
console.log('Synchronisierter Code 2')
lösen()
}).then(() => {
Konsole.log('Versprechen.dann')
})
console.log('Synchronisierter Code 3');
// Endgültige Ausgabe: „Synchronous Code 1“, „Synchronous Code 2“, „Synchronous Code 3“, „promise.then“, „setTimeout“
Die konkrete Analyse lautet wie folgt: - Sowohl setTimeout-Rückrufe als auch promise.then werden asynchron ausgeführt und nach dem gesamten synchronen Code ausgeführt.
- Obwohl promise.then später geschrieben wird, hat seine Ausführungsreihenfolge Vorrang vor setTimeout, da es sich um eine Mikrotask handelt.
- Das neue Promise wird synchron ausgeführt, während der Rückruf in promise.then asynchron erfolgt.
Hinweis: Wenn die Verzögerung „setTimeout“ im Browser auf 0 gesetzt ist, beträgt sie standardmäßig 4 ms und in NodeJS 1 ms. Der wesentliche Unterschied zwischen Mikrotasks und Makrotasks: - Eigenschaften von Makrotasks: Es gibt eindeutige asynchrone Tasks, die ausgeführt und zurückgerufen werden müssen; andere asynchrone Threads müssen diese unterstützen.
- Mikrotask-Eigenschaften: Es müssen keine expliziten asynchronen Tasks ausgeführt werden, sondern nur Rückrufe. Es ist keine weitere asynchrone Thread-Unterstützung erforderlich.
Asynchrone/wartende Ausführungsreihenfolge Merkmale- Die asynchron deklarierte Funktion umschließt einfach die Rückgabe der Funktion, sodass trotzdem ein Promise-Objekt zurückgegeben wird (Nicht-Promise wird in Promise{Resolve} umgewandelt).
- Die „await“-Anweisung kann nur in einer asynchronen Funktion verwendet werden.
- Wenn bei der Ausführung einer asynchronen Funktion eine Await-Anweisung angetroffen wird, wird der Inhalt nach dem Await zuerst entsprechend den „normalen Ausführungsregeln“ ausgeführt (beachten Sie hier, dass, wenn während der Ausführung des Funktionsinhalts erneut eine Await-Anweisung angetroffen wird, der Inhalt der Await-Anweisung als nächstes ausgeführt wird).
- Nach der Ausführung springt es sofort aus der asynchronen Funktion heraus, um andere Inhalte des Hauptthreads auszuführen. Nachdem der Hauptthread ausgeführt wurde, kehrt er zurück, um zu warten, bis die Ausführung der folgenden Inhalte fortgesetzt wird.
Beispiel
const a = async () => {
konsole.log("a");
warte auf b();
warte auf e();
};
const b = async () => {
console.log("b start");
warte auf c();
console.log("b Ende");
};
const c = async () => {
console.log("c start");
warte auf d();
console.log("c Ende");
};
const d = async () => {
konsole.log("d");
};
const e = async () => {
console.log("e");
};
Konsole.log('Start');
A();
konsole.log('Ende');
Ergebnisse der Operation 
Persönliche Analyse- Führen Sie in der aktuellen synchronen Umgebung zuerst console.log('start'); aus, um 'start' auszugeben.
- Wenn Sie auf eine synchrone Funktion a() stoßen, führen Sie a() aus.
- a() ist eine Sync/Await-Konstruktion. Wenn console.log("a") in der Funktion angetroffen wird, wird „a“ ausgegeben. Wenn await angetroffen wird, wird await b() deklariert, was eine asynchrone Funktion ist. Die Ausführung erfolgt in Funktion b(). (Ähnliche Operation, habe ich selbst darüber nachgedacht) und schiebe den Inhalt nach await b() in die Microtask-Warteschlange. Wir können es als [await b()] schreiben.
- b() ist eine Sync/Await-Konstruktion. Bei sequenzieller Ausführung stößt es auf console.log("c start") und gibt „c start“ aus. Bei der Await-Deklaration await c() handelt es sich um eine asynchrone Funktion und wechselt zur Ausführung in die Funktion c(). Und schieben Sie den Inhalt nach „await c()“ in die Microtask-Warteschlange. Wir können es uns als [warte auf c(), dann warte auf b()] merken.
- c() ist eine Sync/Await-Konstruktion. Bei sequenzieller Ausführung wird console.log("b start") gefunden und „b start“ ausgegeben. Wenn es auf die Await-Anweisung await d() stößt, die eine asynchrone Funktion ist, wird die Funktion d() zur Ausführung aufgerufen. Und schieben Sie den Inhalt nach „await d()“ in die Microtask-Warteschlange. Wir können es uns als [warte auf d(), warte auf c(), warte auf b()] merken.
- In d() stößt die sequentielle Ausführung auf console.log(""), das „d“ ausgibt, und die Funktion d() endet.
- Dies geschieht, nachdem d() ausgeführt wurde. Es gibt keine asynchrone Funktion zum Ausführen. Zu diesem Zeitpunkt wird die synchrone Umgebung aufgerufen und der Inhalt nach a() ausgeführt.
- Wenn console.log("end") angetroffen wird, wird „end“ ausgegeben. Zu diesem Zeitpunkt wird der Hauptthread in der synchronen Umgebung ausgeführt und die Mikrotask-Warteschlange überprüft, um festzustellen, ob Mikrotasks vorhanden sind.
- Es gibt Mikrotasks in der Mikrotask-Warteschlange [nach await d(), nach await c(), nach await b()] und der Inhalt nach await d() wird ausgeführt.
- Der Inhalt nach wait d() ist console.log("c end"), das „c end“ ausgibt. An diesem Punkt wird der Inhalt ausgeführt und anschließend in der Mikrotask-Warteschlange [nach „await c()“, nach „await b()“] geprüft, ob der Inhalt nach „await c()“ ausgeführt wird.
- Der Inhalt nach der Ausführung von await c(), console.log("b end");, gibt „b end“ aus. An diesem Punkt wird der Inhalt ausgeführt. Überprüfen Sie anschließend [after await b()] aus der Mikrotask-Warteschlange, ob der Inhalt nach await b() ausgeführt wird.
- Der Inhalt nach await d() ist await e(). Wenn die await-Anweisung angetroffen wird, wird e() ausgeführt. Und beurteilen Sie, dass nach „await e()“ kein Code ausgeführt werden muss. Daher besteht keine Notwendigkeit, in die Aufgabenwarteschlange einzusteigen.
- Führen Sie e() aus, führen Sie dann nacheinander console.log("e"); aus und geben Sie „e“ aus. Die Funktion endet an dieser Stelle.
- Es befindet sich keine Mikrotask in der Mikrotask-Warteschlange [] und die Ausführung wird beendet. Rufen Sie die Synchronisierungsumgebung auf.
Damit ist dieser Artikel zum vertieften Verständnis des Ereignisausführungsmechanismus von JavaScript abgeschlossen. Weitere relevante Inhalte zum Ereignisausführungsmechanismus von JavaScript finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:- Verwenden Sie einige Interviewfragen, um den Ausführungsmechanismus von JavaScript zu untersuchen
- Detaillierte Erklärung des JavaScript-Ausführungsmechanismus
- Den Ausführungsmechanismus von JavaScript genau verstehen
- Eine detaillierte Einführung in den Ausführungsmechanismus von JavaScript
|