Eine kurze Diskussion über die Ausführungsreihenfolge von JavaScript-Makrotasks und Mikrotasks

Eine kurze Diskussion über die Ausführungsreihenfolge von JavaScript-Makrotasks und Mikrotasks

1. JavaScript ist Single-Threaded

JavaScript ist ein Single-Thread-Programm, was bedeutet, dass es immer nur eine Sache gleichzeitig tun kann und die nächste Sache erst ausgeführt werden kann, wenn die vorherige abgeschlossen ist. Dies hat zur Folge, dass der nachfolgende Code nicht ausgeführt werden kann, wenn eine zeitaufwändige Aufgabe auftritt.

Zuvor müssen wir Synchronisation und Asynchronität verstehen

1. Synchrone Aufgaben

    konsole.log(123);
    konsole.log(456);
    für (lass i = 1; i <= 5; i++) {
      konsole.log(i);
    } 

Wie der Name schon sagt, muss es sequentiell ausgeführt werden

2. Asynchrone Aufgaben

    setzeTimeout(() => {
      Konsole.log('Timer');
    }, 0)
    console.log('Ultraman');

Gemäß der normalen Ausführungsreihenfolge steht der Timer oben, daher sollte zuerst der Timer und dann Ultraman ausgegeben werden.

Das Endergebnis ist, dass zuerst Ultraman und dann der Timer ausgegeben wird. Der Grund dafür ist, dass setTimeout eine asynchrone Aufgabe ist.

Noch eine Information: Der Timer von setTimeout ist asynchron, egal wie viele Millisekunden er verzögert wird. Die Zeit ist auch bei jedem Browser anders. Jeder Browser hat seine eigenen Unterschiede, aber das Minimum ist als 0 und 4 Millisekunden definiert.

2. Aufgabenwarteschlange

Aus dem obigen Code wissen wir, dass setTimeout asynchron ist. Wir können die Priorität der Ausführungsreihenfolge verstehen: synchroner Code > asynchroner Code. Daher ist die Aufgabenwarteschlange in zwei Kategorien unterteilt: 1. synchrone Aufgaben 2. asynchrone Aufgaben

1. Ausführungsstapel

(1) Alle synchronen Aufgaben werden auf dem Hauptthread ausgeführt und bilden einen Ausführungskontextstapel.

(2) Neben dem Hauptthread gibt es auch eine „Task-Warteschlange“. Solange die asynchrone Aufgabe ein laufendes Ergebnis hat, wird ein Ereignis in die „Aufgabenwarteschlange“ gestellt.

(3) Sobald alle synchronen Aufgaben im „Ausführungsstapel“ ausgeführt wurden, liest das System die „Aufgabenwarteschlange“, um zu sehen, welche Ereignisse sich darin befinden. Die entsprechenden asynchronen Aufgaben beenden dann den Wartezustand, gelangen in den Ausführungsstapel und beginnen mit der Ausführung.

(4) Der Hauptthread wiederholt den dritten Schritt von oben kontinuierlich. Dies wird als Ereignisschleife bezeichnet.

Gib einfach eine Birne

Sie gehen beide auswärts essen, aber P2 spart die Zeit des Ausgehens.

Nach einem kurzen Verständnis wollen wir einen genaueren Blick auf Makrotasks und Mikrotasks in asynchronen Aufgaben werfen.

Persönliches Verständnis: Makrotasks und Mikrotasks können als zwei Formen der Asynchronität verstanden werden. Asynchronität hat zwei untergeordnete Elemente: Makrotasks und Mikrotasks.

Methoden in Makroaufgaben: 1. Skript (kann als äußerer Synchronisationscode, als Einstiegspunkt verstanden werden) 2. setTimeout/setInterval

Methoden in Mikrotasks: 1. Promise 2. nextTick

Die Reihenfolge ihrer Ausführung ist, dass zuerst Mikrotasks und dann Makrotasks ausgegeben werden.

Code sagen ohne Beweise

    setzeTimeout(() => {
      Konsole.log('Timer');
    }, 0)
    neues Versprechen((lösen) => {
      console.log('synchroner Code')  
      lösen('asynchroner Code')
    }).then((res) => {
      konsole.log(res);   
    })
    console.log('Ultraman'); 

Beachten Sie, dass new Promise einen Konstruktor erstellt, der ein synchroner Prozess ist, während die .then-Methode asynchron ist, sodass der Code zuerst synchron ausgeführt wird > Mikrotask > Makrotask

Um den Ausführungsprozess detaillierter zu beschreiben, ist das folgende Diagramm etwas komplizierter.

Diese Bilder werden kombiniert

Erweitern Sie Ihr Verständnis von setTimeout

Frage 1: Beginnt setTimeout nach der Ausführung des synchronen Codes wieder bei 0 zu zählen?

    setzeTimeout(() => {
      console.log('Zeitüberschreitung festlegen');
    }, 1000);
    console.log('Ultraman');
    für (sei i = 0; i < 1000; i++) {
      konsole.log('');
    } 

An dieser Stelle möchte ich darauf hinweisen, dass setTimeout, wenn ich mich in der for-Schleife befinde, auch ein Timer-Modul startet. Wenn also der Hauptthread ausgeführt wird, hat das Timer-Modul bereits mit der Ausführung begonnen, sodass es nicht 1 Sekunde auf die Ausführung warten muss.

(Gehen Sie nicht davon aus, dass die Synchronisierung abgeschlossen ist und beginnen Sie dann mit der Zeitmessung.)

Frage 2: Soll von den beiden Timern zuerst der obere Timer und dann der untere Timer ausgeführt werden?

Für den Test müssen wir lediglich einen Timer hinzufügen, um zu sehen, wer zuerst ausführt.

    setzeTimeout(() => {
      console.log('setTimeout1');
    }, 2000);
    setzeTimeout(() => {
      console.log('setTimeout2');
    }, 1000); 

Es stellt sich heraus, dass, wenn es zwei Timer gibt, der mit der kürzeren Zeit zuerst im Hauptthread ausgeführt wird.

Frage 3: Wenn eine Variable als 0 definiert ist und zwei identische Timer-Ereignisse festgelegt werden, was ist die Ausgabe? (Interviewfrage)

    ich = 0
    setzeTimeout(() => {
      konsole.log(++i); //1
    }, 1000);
    setzeTimeout(() => {
      konsole.log(++i); //2 
    }, 1000);

Jetzt müssen Sie wissen, dass Timer-Makroaufgaben nicht zusammen, sondern nacheinander ausgeführt werden! !

Interviewfragen zur Ausführungsreihenfolge von Makrotasks und Mikrotasks

    konsole.log('1');
 
    setzeTimeout(Funktion () {
      konsole.log('2');
      Prozess.nextTick(Funktion () {
        konsole.log('3');
      })
      neues Versprechen (Funktion (Auflösung) {
        konsole.log('4');
        lösen();
      }).dann(Funktion () {
        konsole.log('5')
      })
    })
    Prozess.nextTick(Funktion () {
      konsole.log('6');
    })
    neues Versprechen (Funktion (Auflösung) {
      konsole.log('7');
      lösen();
    }).dann(Funktion () {
      konsole.log('8')
    })
 
    setzeTimeout(Funktion () {
      konsole.log('9');
      Prozess.nextTick(Funktion () {
        konsole.log('10');
      })
      neues Versprechen (Funktion (Auflösung) {
        konsole.log('11');
        lösen();
      }).dann(Funktion () {
        konsole.log('12')
      })
    })

Antwort:

Die erste Ausführungsrunde des externen Synchronisationscodes: 1 7

Zweite Runde der Mikrotask-Ausführung: 6 8

Die dritte Runde der Makrotasks: Erstes setTimeout: Synchronisation 2 4 Mikrotask 3 5 Zweites setTimeout: Synchronisation 9 11 Mikrotask 10 12

Gesamtantwort: 1, 7, 6, 8, 2, 4, 3, 5, 9, 11, 10, 12

Damit ist dieser Artikel zur Ausführungsreihenfolge von JavaScript-Makrotasks und -Mikrotasks abgeschlossen. Weitere Informationen zur Ausführungsreihenfolge von JavaScript-Makrotasks und -Mikrotasks finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Details zu Makrotasks und Mikrotasks in JavaScript
  • Eine kurze Diskussion über Makrotasks und Mikrotasks in js
  • JavaScript-Makrotasks und Mikrotasks
  • Eine kurze Diskussion über die Prinzipien von JavaScript-Ereignisschleifen-Mikrotasks und Makrotask-Warteschlangen
  • Analyse der JavaScript-Ereignisschleife sowie der Prinzipien von Makro- und Mikro-Tasks
  • JS-Ereignisschleifenmechanismus Ereignisschleifen-Makrotask-Mikrotask-Prinzipanalyse
  • Erläuterung von JavaScript-Mikrotasks und Makrotasks

<<:  Zusammenfassung der Kenntnisse und der Verwendung von Linux-VI-Befehlen

>>:  Eine vollständige Liste häufig verwendeter MySQL-Funktionen (klassifiziert und zusammengefasst)

Artikel empfehlen

VUE implementiert eine Timeline-Wiedergabekomponente

In diesem Artikelbeispiel wird der spezifische Co...

So erstellen Sie mit Dockerfile ein Spiegelbild der Java-Laufzeitumgebung

Die aktuelle Umgebung ist: Centos 7.5 docker-ce 1...

Beispiele für JavaScript-Entschüttelungen und Drosselung

Inhaltsverzeichnis Stabilisierung Drosselung: Ant...

Verwendung des Linux-Datumsbefehls

1. Befehlseinführung Mit dem Datumsbefehl wird di...

Verwenden von Vue3 (Teil 1) Erstellen eines Vue CLI-Projekts

Inhaltsverzeichnis 1. Offizielle Dokumentation 2....

MySQL 8.0.15 Installations-Tutorial für Windows 64-Bit

Gehen Sie zunächst zum Herunterladen auf die offi...

Umfassendes Verständnis des html.css-Überlaufs

Umfassendes Verständnis des html.css-Überlaufs XM...

JS+Canvas zeichnet ein Glücksrad

In diesem Artikel wird der spezifische Code der J...

Vollbild-Drag-Upload-Komponente basierend auf Vue3

In diesem Artikel wird hauptsächlich die Vollbild...

Zwei Möglichkeiten zum Starten des Linux-Bootdienstes

Inhaltsverzeichnis rc.local-Methode chkconfig-Met...

Detaillierte Erklärung der Serveroptionen von Tomcat

1. Konfiguration Die ersten beiden sind standardm...