Vorwort:Dieses Mal werde ich hauptsächlich mein Verständnis des Js-Ereignisschleifenmechanismus, der Synchronisierung, der asynchronen Aufgaben, der Makroaufgaben und der Mikroaufgaben klären. Es besteht eine hohe Wahrscheinlichkeit, dass vorerst noch einige Abweichungen oder Fehler auftreten. Wenn ja, können Sie meine Fehler gerne korrigieren! 1. Gründe für die Ereignisschleife und die Aufgabenwarteschlange:Erstens ist JS ein Single-Thread, daher ist dieses Design sinnvoll. Stellen Sie sich vor, der DOM wird auf einer Seite gelöscht und auf der anderen Seite hinzugefügt. Wie soll der Browser damit umgehen? Zitat: „ Single-Threaded bedeutet, dass die Aufgaben seriell ausgeführt werden und die nächste Aufgabe warten muss, bis die vorherige Aufgabe ausgeführt wurde, was zu einer langen Wartezeit führen kann. Aufgrund von Aufgaben wie Ajax-Netzwerkanforderungen, SetTimeout-Zeitverzögerungen und Benutzerinteraktionen mit DOM-Ereignissen verbrauchen diese Aufgaben jedoch keine CPU und sind eine Verschwendung von Ressourcen. Daher tritt Asynchronität auf. Durch die Zuweisung von Aufgaben zur Verarbeitung an entsprechende asynchrone Module wird die Effizienz des Hauptthreads erheblich verbessert und andere Vorgänge können parallel verarbeitet werden. Wenn die asynchrone Verarbeitung abgeschlossen ist und der Hauptthread inaktiv ist, liest der Hauptthread den entsprechenden Rückruf und führt nachfolgende Vorgänge aus, um die CPU-Nutzung zu maximieren. Zu diesem Zeitpunkt treten die Konzepte der synchronen Ausführung und der asynchronen Ausführung auf. Synchrone Ausführung bedeutet, dass der Hauptthread Aufgaben nacheinander und seriell ausführt; asynchrone Ausführung bedeutet, dass die CPU das Warten überspringt und nachfolgende Aufgaben zuerst verarbeitet (die CPU führt Aufgaben parallel mit Netzwerkmodulen, Timern usw. aus). Dadurch werden Aufgabenwarteschlangen und Ereignisschleifen erstellt, um die Arbeit zwischen dem Hauptthread und den asynchronen Modulen zu koordinieren. “ zwei, Ereignisschleifenmechanismus:Diagramm: Zunächst wird die JS-Ausführungscodeoperation Schritt 1: Der Hauptthread liest den JS-Code, der eine synchrone Umgebung darstellt, und bildet den entsprechenden Heap und Ausführungsstapel. Zu den üblichen asynchronen Vorgängen zählen: Ajax-Anfragen, „setTimeout“ und ähnliche Onclik-Ereignisse usw. drei, Aufgabenwarteschlange:Synchrone und asynchrone Aufgaben gelangen jeweils in unterschiedliche Ausführungsumgebungen. Synchrone Aufgaben gelangen in den Hauptthread, also den Hauptausführungsstapel, und asynchrone Aufgaben gelangen in die Aufgabenwarteschlange. Zunächst einmal folgt es, wie der Name schon sagt, da es sich um eine Warteschlange handelt, Wie im Diagramm oben gezeigt, gibt es mehrere Aufgabenwarteschlangen und ihre Ausführungsreihenfolge ist: In derselben Aufgabenwarteschlange werden Aufgaben vom Hauptthread in der Reihenfolge der Warteschlange weggenommen. 3.1 Arten von Aufgabenwarteschlangen: Die Aufgabenwarteschlange ist in Zu den Makroaufgaben gehören hauptsächlich: Skript (gesamter Code), setTimeout, setInterval, I/O, UI-Interaktionsereignisse, setImmediate (Node.js-Umgebung) Zu den Mikrotasks gehören hauptsächlich: Promise, MutaionObserver, process.nextTick (Node.js-Umgebung) 3.2 Der Unterschied zwischen den beiden: (1) Eindeutig, es gibt nur eines in der gesamten Ereignisschleife; PS: Daher kann die Mikrotask-Warteschlange eine synchrone Ausführungsumgebung bilden Makrotask- (1) Nicht eindeutig, es gibt eine bestimmte Priorität (der Benutzer-E/A-Teil hat eine höhere Priorität) 3.3 Ein detaillierterer Event-Loop-Prozess
Lassen Sie uns zur Vertiefung unseres Verständnisses ein einfaches Beispiel verwenden: console.log('1, time = ' + new Date().toString()) // 1. Rufen Sie den Hauptthread auf, führen Sie Synchronisierungsaufgaben aus und geben Sie 1 aus setTimeout(macroCallback, 0) // 2. Treten Sie der Makro-Task-Warteschlange bei // 7. Starten Sie die Ausführung dieses Timer-Makro-Tasks, rufen Sie macroCallback auf und geben Sie 4 aus new Promise(function (resolve, reject) { //3. Treten Sie der Microtask-Warteschlange bei console.log('2, time = ' + new Date().toString()) //4. Führen Sie den Synchronisierungscode in diesem Microtask aus und geben Sie 2 aus lösen() console.log('3, time = ' + new Date().toString()) //5. Ausgabe 3 }).then(microCallback) // 6. Führe den then-Microtask aus, rufe microCallback auf und gebe 5 aus //Funktionsdefinition Funktion macroCallback() { Konsole.log('4, Zeit = ' + neues Datum().toString()) } Funktion MikroCallback() { Konsole.log('5, Zeit = ' + neues Datum().toString()) } Laufergebnisse: Vier, Leistungsstarker asynchroner Experte process.nextTick() Als ich dieses Ding zum ersten Mal sah, kam es mir bekannt vor. Ich dachte darüber nach und es schien, als hätte ich 4.1 Wann wird process.nextTick() aufgerufen?Immer wenn process.nextTick() während einer bestimmten Phase aufgerufen wird, werden alle an process.nextTick() übergebenen Rückrufe aufgelöst, bevor die Ereignisschleife fortgesetzt wird. In der Ereignisschleife wird jeder Schleifenvorgang Lassen Sie uns die Beispiele anderer Leute übernehmen, um unser Verständnis der Ereignisschleife zu vertiefen: var flag = false // 1. Variablendeklaration Promise.resolve().then(() => { // 2. Verteile die then-Aufgabe an die Mikrotask-Warteschlange dieser Schleifenrunde console.log('then1') // 8. Führe die then-Mikrotask aus, drucke then1 aus und das Flag ist zu diesem Zeitpunkt wahr flag = true }) neues Versprechen(lösen => { // 3. Führen Sie den synchronen Code in Promise aus console.log('promise') lösen() setTimeout(() => { // 4. Setze die Aufgabe im Timer in die Warteschlange der Makroaufgaben console.log('timeout2') // 11. Führe die Timer-Makroaufgabe aus. Hier ist eine Wartezeit von 10 angegeben, sodass sie nach einer anderen Timeraufgabe ausgeführt wird}, 10) }).dann(Funktion () { // 5. Verteile die then-Aufgabe an die Microtask-Warteschlange dieser Schleifenrunde console.log('then2') // 9. Führe die then-Microtask aus und drucke then2 aus. Diese Tick-Runde endet}) Funktion f1(f) { // 1. Funktionsdeklaration f() } Funktion f2(f) { // 1. Funktionsdeklaration setTimeout(f) // 7. Setze „f“ in „setTimeout“ in die Warteschlange der Makroaufgabe ein, warte auf die Ausführung der aktuellen Runde von „tick“ und führe es dann in der nächsten Ereignisschleife aus} f1(() => console.log('f ist:', flag ? 'asynchronous' : 'synchronous')) // 6. Drucken Sie `f ist: synchronous` f2(() => { console.log('timeout1,', 'f is:', flag ? 'asynchronous' : 'synchronous') // 10. Timer-Makro-Task ausführen}) console.log('Diese Runde der Makroaufgaben wurde ausgeführt') // 7. Drucken Laufergebnisse: Der Rückruf in process.nextTick wird aufgerufen, nachdem der aktuelle Tick ausgeführt wurde und bevor die nächste Makroaufgabe ausgeführt wird. Offizielles Beispiel: lass bar; // Diese Methode verwendet eine asynchrone Signatur, ruft die Rückruffunktion aber tatsächlich synchron auf someAsyncApiCall(callback) { callback(); } // Rückruffunktion wird aufgerufen, bevor `someAsyncApiCall` abgeschlossen istsomeAsyncApiCall(() => { // bar wird kein Wert zugewiesen, da `someAsyncApiCall` abgeschlossen ist console.log('bar', bar); // undefiniert }); Balken = 1; Verwenden Sie lass bar; Funktion someAsyncApiCall(Rückruf) { Prozess.nextTick(Rückruf); } einigeAsyncApiCall(() => { console.log('bar', bar); // 1 }); Balken = 1; Schauen wir uns ein weiteres Beispiel mit console.log('1'); // 1. In den Ausführungsstapel des Hauptthreads einfügen und 1 ausgeben setTimeout(function () { //2. Seine Rückruffunktion wird zur Warteschlange der Makroaufgaben hinzugefügt //7. Derzeit ist die Warteschlange der Mikroaufgaben leer. Nehmen Sie daher das erste Element aus der Warteschlange der Makroaufgaben heraus und führen Sie diese Aufgabe aus console.log('2'); // Ausgabe 2 process.nextTick(function () { // 16. Die letzte Schleife endet, aufgerufen, bevor die nächste Makroaufgabe startet, Ausgabe 3 konsole.log('3'); }) neues Versprechen (Funktion (Auflösung) { //8. Führen Sie die Synchronisierungsaufgabe dieses Versprechens aus, geben Sie 4 aus, und der Status wird aufgelöst konsole.log('4'); lösen(); }).then(function () {//9. Erkenne dann die asynchrone Methode und füge ihre Rückruffunktion zur Microtask-Warteschlange hinzu console.log('5'); // 10. Nimm das erste Element in der Microtask-Warteschlange heraus, das der Rückruf davon ist, führe es aus und gib 5 aus }) }) process.nextTick(function () { // 11. Sobald die Ereignisschleife endet, führen Sie den Rückruf von nextTick() aus und geben Sie 6 aus konsole.log('6'); }) neues Versprechen (Funktion (Auflösung) { //3. Führen Sie die synchrone Aufgabe im Versprechen aus und geben Sie 7 aus. Der Status ändert sich in „Aufgelöst“. konsole.log('7'); lösen(); }).then(function () { //4. Erkenne dann die asynchrone Methode und füge ihre Rückruffunktion zur Microtask-Warteschlange hinzu console.log('8'); //6. Der Hauptthread wird ausgeführt, nimmt das erste Element aus der Microtask-Warteschlange, schiebt seine Rückruffunktion in den Ausführungsstapel und gibt 8 aus }) setTimeout(function () { //5. Seine Rückruffunktion wird zur Warteschlange der Makroaufgabe hinzugefügt //12. Zu diesem Zeitpunkt ist die Warteschlange der Mikroaufgabe leer und die Makroaufgabe wird ausgeführt console.log('9'); // Ausgabe 9 process.nextTick(function () { // 17. Zu diesem Zeitpunkt sind sowohl die Warteschlangen für Mikro- als auch für Makroaufgaben leer, die Schleife endet automatisch, führt diesen Rückruf aus und gibt 10 aus konsole.log('10'); }) neues Versprechen (Funktion (Auflösung) { //13. Führen Sie die Synchronisierungsaufgabe dieses Versprechens aus, geben Sie 11 aus und der Status ändert sich console.log('11'); lösen(); }).then(function () {//14. Erkennen Sie die asynchrone Methode then und fügen Sie sie der Microtask-Warteschlange hinzu console.log('12');//15. Nehmen Sie das erste Element aus der Microtask-Warteschlange, führen Sie diese then-Mikrotask aus und geben Sie 12 aus }) }) Laufergebnisse: Dieser Vorgang wird im Detail erklärt:
Beenden! Wenn mir die Inspiration kommt, schreibe ich sie schnell auf und schaue später, ob es Probleme gibt. Sie können mich auch gerne auf meine Fehler hinweisen. Lassen Sie uns ein einfaches Beispiel analysieren: konsole.log('0'); setzeTimeout(() => { konsole.log('1'); neues Versprechen(Funktion(Auflösung) { konsole.log('2'); lösen(); }).dann(()=>{ konsole.log('3'); }) neues Versprechen(lösen => { konsole.log('4'); für (lass i = 0; i < 9; i++) { i == 7 und lösen(); } konsole.log('5'); }).then(() => { konsole.log('6'); }) })
Ergebnisse der Codeausführung: Dies ist das Ende dieses Artikels über die Analyse des Ereignisschleifenmechanismus von JavaScript. Weitere relevante Inhalte zum Ereignisschleifenmechanismus 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:
|
>>: Beispiel für die Einstellung des HTML-Hyperlink-Stils (vier verschiedene Zustände)
Dieser Artikel beschreibt anhand eines Beispiels ...
1. Was ist In react Anwendungen werden Ereignisna...
Wenn Sie eine virtuelle Maschine verwenden, stell...
Quellcode herunterladen Git-Klon https://github.c...
Wirkung: Wenn sich die Diashow in eine Richtung b...
Inhaltsverzeichnis 2. Feldverkettung 2. Geben Sie...
Inhaltsverzeichnis Was ist bei der Registrierung ...
Bei meinen letzten Studien habe ich einige Layout...
Virtuelle Linux-Maschine: VMware + Ubuntu 16.04.4...
Bei Ubuntu 20.04 ist die Root-Anmeldung standardm...
Dieser Artikel beschreibt anhand eines Beispiels ...
In requireJS gibt es eine Eigenschaft namens base...
Was ist der Unterschied zwischen der grünen Versi...
Aktivieren Sie den Remotezugriff auf MySQL MySQL-...
In meiner Verzweiflung dachte ich plötzlich: Wie i...