So können Sie schnell mit VUE3.0 beginnen: Erfahren Sie mehr
über den Ausführungskontext, den Ausführungsstapel und den Ausführungsmechanismus (synchrone Aufgaben, asynchrone Aufgaben, Mikrotasks, Makrotasks und Ereignisschleifen) in js
Dies ist ein häufiger Testpunkt in Interviews Einige Freunde sind möglicherweise verwirrt, wenn Sie gefragt werden. Deshalb werde ich es heute zusammenfassen und hoffe, dass es Ihnen vor dem Bildschirm hilfreich sein kann.
Bevor wir über den Ausführungskontext und js
-Ausführungsmechanismus in js
sprechen, sprechen wir über Threads und Prozesse.
In offiziellen Begriffen ist线程
die kleinste Einheit der CPU
Planung.
? Offiziell ist进程
die kleinste Einheit der CPU
Ressourcenzuweisung.
线程
ist eine Programmlaufeinheit, die auf进程
basiert. Laienhaft ausgedrückt ist线程
ein Ausführungsablauf in einem Programm. Ein进程
kann einen oder mehrere线程
haben.
Es gibt nur einen Ausführungsfluss in einem进程
, der单线程
bezeichnet wird. Das heißt, wenn das Programm ausgeführt wird, werden die verwendeten Programmpfade in aufeinanderfolgender Reihenfolge angeordnet. Die vorherigen müssen verarbeitet werden, bevor die späteren ausgeführt werden.
Mehrere Ausführungsströme in einem进程
werden als多线程
bezeichnet. Das heißt, mehrere verschiedene线程
können gleichzeitig in einem Programm ausgeführt werden, um unterschiedliche Aufgaben auszuführen. Dies bedeutet, dass ein einzelnes Programm mehrere parallele线程
erstellen darf, um ihre jeweiligen Aufgaben auszuführen. .
Der Autor gibt unten ein einfaches Beispiel: Wenn wir qq音乐
öffnen und Lieder anhören, können wir qq音乐
als einen Prozess verstehen qq音乐
wir herunterladen können Zu Liedern ist ein Thread, und das Herunterladen ist ein Prozess. Wenn wir vscode
erneut öffnen, um Code zu schreiben, ist dies ein weiterer Vorgang.
Prozesse sind unabhängig voneinander, einige Ressourcen werden jedoch von Threads unter demselben Prozess gemeinsam genutzt.
Der Lebenszyklus eines Threads durchläuft fünf Phasen.
Neuer Status: Nachdem das Schlüsselwort new
und Thread
-Klasse oder ihre Unterklasse zum Erstellen eines Thread-Objekts verwendet wurden, befindet sich das Thread-Objekt im neuen Status. Es bleibt in diesem Zustand, bis das Programm den Thread start()
.
Bereitzustand: Wenn das Thread-Objekt start()
aufruft, wechselt der Thread in den Bereitschaftszustand. Der Thread im Bereitschaftszustand befindet sich in der Bereitschaftswarteschlange und kann sofort ausgeführt werden, sofern er das Recht zur Nutzung CPU
erhält.
Ausführungsstatus: Wenn der Thread im Bereitschaftsstatus CPU
Ressourcen erhält, kann er run()
ausführen und der Thread befindet sich im Ausführungsstatus. Der Thread im laufenden Zustand ist am komplexesten, er kann blockiert, bereit und tot werden.
Blockierungsstatus: Wenn ein Thread die Methoden sleep(睡眠)
, suspend(挂起)
, wait(等待)
und andere ausführt, wechselt der Thread nach dem Verlust der belegten Ressourcen aus dem laufenden Status in den Blockierungsstatus. Der Bereitschaftszustand kann wieder aktiviert werden, nachdem die Ruhezeit abgelaufen ist oder Geräteressourcen abgerufen wurden. Es kann in drei Typen unterteilt werden:
Warteblockierung: Der Thread im laufenden Zustand führt wait()
aus, wodurch der Thread in den Warteblockierungsstatus wechselt.
Synchronblockierung: Der Thread kann die synchronized
Synchronisationssperre nicht erhalten (da die Synchronisationssperre von anderen Threads belegt ist).
Andere Blockierung: Wenn I/O
Anfrage durch den Aufruf von sleep()
oder join()
des Threads ausgegeben wird, wechselt der Thread in den Blockierungszustand. Wenn sleep()
abläuft, wartet join()
auf die Beendigung oder Zeitüberschreitung des Threads oder auf den Abschluss der I/O
-Verarbeitung und der Thread kehrt in den Bereitschaftszustand zurück.
Todeszustand: Wenn ein laufender Thread seine Aufgabe abschließt oder andere Beendigungsbedingungen auftreten, wechselt der Thread in den beendeten Zustand.
JS
ist Single-Threaded. Als Browser-Skriptsprache wird JS
hauptsächlich zur Interaktion mit Benutzern und zur Bedienung DOM
verwendet. Dies legt fest, dass es nur Single-Threaded sein kann, da es sonst zu sehr komplexen Synchronisationsproblemen kommt. Angenommen, JavaScript
verfügt über zwei Threads gleichzeitig. Ein Thread fügt Inhalt zu einem bestimmten DOM
Knoten hinzu und der andere Thread löscht den Knoten. Welchen Thread sollte der Browser in diesem Fall verwenden?
Wenn JS
Engine ein ausführbares Codefragment analysiert (normalerweise die Funktionsaufrufphase), führt sie vor der Ausführung zunächst einige vorbereitende Arbeiten durch. (Ausführungskontext (als EC
bezeichnet)“ oder kann auch als Ausführungsumgebung bezeichnet werden.
Es gibt drei Ausführungskontexttypen in javascript
:
Globaler Ausführungskontext . Dies ist der Standard- oder grundlegendste Ausführungskontext. Es gibt nur einen globalen Kontext in einem Programm, der während des gesamten Lebenszyklus vorhanden ist javascript
Skript. Der untere Teil des Ausführungsstapels wird durch das Stapeln nicht zerstört. Der globale Kontext generiert ein globales Objekt (am Beispiel der Browserumgebung ist dieses globale Objekt window
) und bindet this
Wert an dieses globale Objekt.
Funktionsausführungskontext Bei jedem Aufruf einer Funktion wird ein neuer Funktionsausführungskontext erstellt (unabhängig davon, ob die Funktion wiederholt aufgerufen wird).
Ausführungskontext der Eval-Funktion Der in eval
Funktion ausgeführte Code verfügt ebenfalls über einen eigenen Ausführungskontext. Da eval
jedoch nicht häufig verwendet wird, wird er hier nicht analysiert.
Wir haben bereits erwähnt, dass js
beim Ausführen einen Ausführungskontext erstellt, der Ausführungskontext jedoch gespeichert werden muss. Womit wird er also gespeichert? Sie müssen die Stapeldatenstruktur verwenden.
Der Stapel ist eine First-In-Last-Out-Datenstruktur.
Zusammenfassend ist der Ausführungskontext, der zum Speichern des beim Ausführen des Codes erstellten Ausführungskontexts verwendet wird, der Ausführungsstapel .
Beim Ausführen eines Codeabschnitts JS
Anschließend erstellt JS
Engine einen globalen Ausführungskontext und push
auf den Ausführungsstapel. In diesem Prozess weist JS
Engine allen Variablen in diesem Code einen Anfangswert zu (undefiniert). Die JS
Engine tritt in die Ausführungsphase ein. In diesem Prozess führt JS
Engine den Code Zeile für Zeile aus, dh weist den Variablen, denen Speicher zugewiesen wurde, nacheinander Werte (reale Werte) zu.
Wenn in diesem Code function
vorhanden ist, erstellt JS
Engine einen Funktionsausführungskontext und push
auf den Ausführungsstapel. Der Erstellungs- und Ausführungsprozess ist der gleiche wie der globale Ausführungskontext.
Wenn ein Ausführungsstapel abgeschlossen ist, wird der Ausführungskontext vom Stapel entfernt und dann wird der nächste Ausführungskontext eingegeben.
Lassen Sie mich unten ein Beispiel geben. Wenn wir den folgenden Code in unserem Programm haben:
console.log("Global Execution Context start"); Funktion first() { console.log("erste Funktion"); zweite(); console.log("Wieder erste Funktion"); } Funktion second() { console.log("zweite Funktion"); } Erste(); console.log("Global Execution Context end");
Lassen Sie uns das obige Beispiel kurz analysieren.
Zuerst wird ein Ausführungsstapel erstellt
, dann wird ein globaler Kontext erstellt und der Ausführungskontext wird auf den Ausführungsstapel push
,
um die Ausführung zu starten , und Global Execution Context start
trifft auf first
Methode, führt die Methode aus, erstellt einen Funktionsausführungskontext und push
auf den Ausführungsstapel,
um first
Ausführungskontext auszuführen, gibt die first function
aus,
trifft auf second
Methode und führt die Methode aus , erstellt einen Funktionsausführungskontext und push
auf den Ausführungsstapel, um
second
Ausführungskontext auszuführen, die zweite second function
second
ausgeführt, vom Stapel entfernt und in den nächsten Ausführungskontext eingegeben first
first
Ausführungskontext wird fortgesetzt Ausführung, Ausgabe Again first function
wurde die erste Funktion ausgeführt, vom Stapel entfernt und in den nächsten Ausführungskontext eingegeben. first
Ausführungskontext.
Globaler Ausführungskontext. Ausführung und Ausgabe fortsetzen. Global Execution Context end
Wir verwenden ein Bild zur Zusammenfassung
In Ordnung. Nachdem wir über den Ausführungskontext und den Ausführungsstapel gesprochen haben, sprechen wir über den Ausführungsmechanismus von js. Wenn wir über den Ausführungsmechanismus von js
sprechen
müssen js
die synchronen Aufgaben, asynchronen Aufgaben, Makroaufgaben und Mikroaufgaben in js
verstehen.
In js
werden Aufgaben in synchrone Aufgaben und asynchrone Aufgaben unterteilt. Was sind also synchrone Aufgaben und was sind asynchrone Aufgaben?
Synchrone Aufgaben beziehen sich auf Aufgaben, die zur Ausführung im Hauptthread in die Warteschlange gestellt werden. Die nächste Aufgabe kann erst ausgeführt werden, nachdem die vorherige Aufgabe ausgeführt wurde.
Asynchrone Aufgaben beziehen sich auf Aufgaben, die nicht in den Hauptthread, sondern in die „Aufgabenwarteschlange“ gelangen (Aufgaben in der Aufgabenwarteschlange werden nur dann parallel zum Hauptthread ausgeführt, wenn der Hauptthread inaktiv ist und die „Aufgabenwarteschlange“ benachrichtigt wird). Hauptthread, eine asynchrone Aufgabe Sobald sie ausgeführt werden kann, wird die Aufgabe zur Ausführung in den Hauptthread eingegeben. Da es sich um einen Warteschlangenspeicher handelt, erfüllt er die First-In-First-Out-Regel . Zu den gängigen asynchronen Aufgaben gehören setInterval
, setTimeout
, promise.then
usw.
hat zuvor synchrone Aufgaben und asynchrone Aufgaben eingeführt. Lassen Sie uns nun über die Ereignisschleife sprechen.
Synchrone und asynchrone Aufgaben gelangen jeweils an unterschiedliche Ausführungsorte und gelangen synchron in den Hauptthread. Erst wenn die vorherige Aufgabe abgeschlossen ist, kann die nächste Aufgabe ausgeführt werden. Asynchrone Aufgaben gelangen nicht in den Hauptthread, sondern in Event Table
und registrieren Funktionen.
Wenn die angegebene Sache abgeschlossen ist, verschiebt Event Table
diese Funktion in Event Queue
. Event Queue
ist eine Warteschlangendatenstruktur und erfüllt daher die First-In-First-Out-Regel.
Wenn die Aufgaben im Hauptthread nach der Ausführung leer sind, wird die entsprechende Funktion aus Event Queue
gelesen und im Hauptthread ausgeführt.
Der obige Vorgang wird kontinuierlich wiederholt, was oft als Ereignisschleife bezeichnet wird.
Fassen wir es mit einem Bild zusammen
Lassen Sie mich kurz eine Beispielfunktion
test1() {vorstellen
console.log("log1"); setTimeout(() => { console.log("setTimeout 1000"); }, 1000); setTimeout(() => { console.log("setTimeout 100"); }, 100); console.log("log2"); } test1(); // log1, log2, setTimeout 100, setTimeout 1000
Wir wissen, dass in js synchrone Aufgaben zuerst vor asynchronen Aufgaben ausgeführt werden, daher werden im obigen Beispiel zuerst log1、log2
ausgegeben
und dann asynchrone Aufgaben nach den synchronen ausgeführt
1000
setTimeout 1000
die Rückruffunktion mit einer Verzögerung von 100
Millisekunden zuerst die Ausgabe setTimeout 100
aus.
Das obige Beispiel ist meiner Meinung nach relativ einfach Solange Sie die vom Autor oben erwähnten synchronen und asynchronen Aufgaben verstehen, wird es kein Problem geben. Dann möchte ich Ihnen noch ein Beispiel geben, Freunde, mal sehen, wie das Ergebnis aussehen wird.
Funktion test2() { console.log("log1"); setTimeout(() => { console.log("setTimeout 1000"); }, 1000); setTimeout(() => { console.log("setTimeout 100"); }, 100); neues Versprechen((auflösen, ablehnen) => { console.log("neues Versprechen"); lösen(); }).then(() => { console.log("promise.then"); }); console.log("log2"); } test2();
Um das obige Problem zu lösen, reicht es nicht aus, synchrone und asynchrone Aufgaben zu kennen. Wir müssen auch Makroaufgaben und Mikroaufgaben kennen.
In js
werden Aufgaben in zwei Typen unterteilt, einer heißt Makroaufgabe MacroTask
und der andere heißt Mikroaufgabe MicroTask
.
Die gemeinsame Makroaufgabe MacroTask
hat
den Hauptcodeblock
setTimeout()
setInterval()
setImmediate() - Knoten
requestAnimationFrame() -
Der gemeinsame Mikroaufgabe MicroTask
hat
Promise.then()
Process.nextTick() -
Knoten obiges Beispiel Es handelt sich um Makroaufgaben und Mikroaufgaben. Wie ist die Ausführungsreihenfolge von Makroaufgaben und Mikroaufgaben?
Wenn das gesamte script
(als erste Makroaufgabe) ausgeführt wird, wird zunächst der gesamte Code in zwei Teile unterteilt: synchrone Aufgaben und asynchrone Aufgaben. Die synchronen Aufgaben werden direkt in den Hauptthread eingegeben und nacheinander ausgeführt. und die asynchronen Aufgaben werden in die asynchrone Warteschlange eingegeben und dann in Makroaufgaben und Mikroaufgaben unterteilt.
Die Makroaufgabe tritt in Event Table
ein und registriert darin eine Rückruffunktion. Immer wenn das angegebene Ereignis abgeschlossen ist, verschiebt Event Table
diese Event Queue
in die Event Table
Sobald das angegebene Ereignis abgeschlossen ist, verschiebt Event Table
diese Funktion in Event Queue
Event Queue
die Aufgaben im Hauptthread abgeschlossen sind und der Hauptthread leer ist, wird überprüft, ob Aufgaben vorhanden sind , alle Ausführen, wenn nicht, führen Sie die nächste Makroaufgabe aus.
Wir verwenden ein Bild, um es zusammenzufassen.
Nachdem wir die obigen Beispiele für asynchrone Makroaufgaben und Mikroaufgaben verstanden haben, können wir leicht die Antwort erhalten.
Wir wissen, dass in js synchrone Aufgaben zuerst vor asynchronen Aufgaben ausgeführt werden, sodass im obigen Beispiel zuerst log1、new promise、log2
ausgegeben werden. Hierbei ist zu beachten, dass der Hauptcodeblock des neuen Versprechens synchronisiert wird.
Nachdem die Makroaufgabe ausgeführt wurde, werden alle von dieser Makroaufgabe generierten Mikroaufgaben ausgeführt, sodass promise.then
ausgegeben
wird , eine weitere Makroaufgabe wird ausgeführt, die Rückruffunktion wird um 100
Millisekunden verzögert und priorisiert die Ausführung und gibt setTimeout 100
aus.
Diese Makroaufgabe generiert keine Mikroaufgaben, sodass keine Mikroaufgaben ausgeführt werden müssen,
um mit der Ausführung der nächsten Makroaufgabe fortzufahren Die Funktion mit einer Verzögerung von 1000
priorisiert die Ausführung und gibt setTimeout 1000
Nachdem die Methode test2 ausgeführt wurde, werden log1、new promise、log2、promise.then、setTimeout 100、setTimeout 1000
nacheinander
ausgegeben Es gibt unterschiedliche Meinungen darüber, ob
js
zuerst mit Makroaufgaben und dann mit Mikroaufgaben oder mit Mikroaufgaben vor Makroaufgaben ausgeführt werden soll. Das Verständnis des Autors ist, dass, wenn der gesamtejs
Codeblock als Makroaufgabe betrachtet wird, unserejs
Ausführungsreihenfolge zuerst die Makroaufgabe und dann die Mikroaufgabe ist.
Wie das Sprichwort sagt: Einmal üben ist besser als hundertmal zuschauen. Im Folgenden gebe ich Ihnen zwei Beispiele. Wenn Sie es richtig machen, beherrschen Sie die Kenntnisse über den Ausführungsmechanismus von js
.
Beispiel 1
Funktion test3() { console.log(1); setTimeout(function () { console.log(2); neues Versprechen(Funktion (Auflösung) { console.log(3); lösen(); }).then(function () { console.log(4); }); console.log(5); }, 1000); neues Versprechen(Funktion (Auflösung) { console.log(6); lösen(); }).then(function () { console.log(7); setTimeout(function () { console.log(8); }); }); setTimeout(function () { console.log(9); neues Versprechen(Funktion (Auflösung) { console.log(10); lösen(); }).then(function () { console.log(11); }); }, 100); console.log(12); } test3();
Lassen Sie es uns im Detail analysieren.
Zuerst wird der gesamte js
Codeblock als Makroaufgabe ausgeführt und 1, 1、6、12
werden nacheinander ausgegeben.
Nachdem die gesamte Codeblock-Makroaufgabe ausgeführt wurde, werden eine Mikroaufgabe und zwei Makroaufgaben generiert, sodass die Makroaufgabenwarteschlange zwei Makroaufgaben und die Mikroaufgabenwarteschlange eine Mikroaufgabe enthält.
Nachdem die Makroaufgabe ausgeführt wurde, werden alle von dieser Makroaufgabe generierten Mikroaufgaben ausgeführt. Da es nur eine Mikrotask gibt, werden 7
ausgegeben. Diese Mikrotask hat eine weitere Makrotask hervorgebracht, sodass sich derzeit drei Makrotasks in der Makrotask-Warteschlange befinden.
Von den drei Makrotasks wird diejenige ohne festgelegte Verzögerung zuerst ausgeführt, sodass 8
ausgegeben wird. Diese Makrotask generiert keine Mikrotasks, sodass keine Mikrotasks ausgeführt werden müssen, und die nächste Makrotask wird weiterhin ausgeführt.
Verzögern Sie die Ausführung der Makrotask um 100
Millisekunden, geben Sie 9、10
aus und generieren Sie eine Mikrotask, sodass die Mikrotask-Warteschlange derzeit über eine Mikrotask verfügt.
Nachdem die Makrotask ausgeführt wurde, werden alle von der Makrotask generierten Mikrotasks ausgeführt Alle Mikrotasks in der Task-Warteschlange geben 11
aus.
Die Makrotask-Ausführung erfolgt 2、3、5
einer Verzögerung von 1000
Millisekunden. Daher verfügt die Mikrotask-Warteschlange derzeit über eine Mikrotask
. Die Makrotask wird ausgeführt, sodass alle Mikrotasks in der Mikrotask-Warteschlange ausgeführt werden und 4
ausgegeben werden
. Das obige Codebeispiel gibt also 1、6、12、7、8、9、10、11、2、3、5、4
, 12, 7, 8, 9, 10, 11 aus , 2, 3, 5, 4 nacheinander. Habt ihr es richtig gemacht?
Beispiel 2:
Wir modifizieren das obige Beispiel 1 leicht und führen async
und await
asynchrone Funktion test4() {ein.
console.log(1); setTimeout(function () { console.log(2); neues Versprechen(Funktion (Auflösung) { console.log(3); lösen(); }).then(function () { console.log(4); }); console.log(5); }, 1000); neues Versprechen(Funktion (Auflösung) { console.log(6); lösen(); }).then(function () { console.log(7); setTimeout(function () { console.log(8); }); }); const result = wait async1(); console.log(result); setTimeout(function () { console.log(9); neues Versprechen(Funktion (Auflösung) { console.log(10); lösen(); }).then(function () { console.log(11); }); }, 100); console.log(12); } asynchrone Funktion async1() { console.log(13) return Promise.resolve("Promise.resolve"); } test4();
Was wird das obige Beispiel ausgeben? Hier können wir das Problem von async
und await
leicht lösen.
Wir wissen async
und await
tatsächlich Syntaxzucker für Promise
sind. Hier müssen wir nur wissen, await
äquivalent zu Promise.then
ist. Daher können wir das obige Beispiel als folgenden Code verstehen:
Funktion test4() { console.log(1); setTimeout(function () { console.log(2); neues Versprechen(Funktion (Auflösung) { console.log(3); lösen(); }).then(function () { console.log(4); }); console.log(5); }, 1000); neues Versprechen(Funktion (Auflösung) { console.log(6); lösen(); }).then(function () { console.log(7); setTimeout(function () { console.log(8); }); }); neues Versprechen(Funktion (Auflösung) { console.log(13); return discover("Promise.resolve"); }).then((result) => { console.log(result); setTimeout(function () { console.log(9); neues Versprechen(Funktion (Auflösung) { console.log(10); lösen(); }).then(function () { console.log(11); }); }, 100); console.log(12); }); } test4();
Können Sie das Ergebnis leicht erhalten, nachdem Sie den obigen Code gesehen haben?
Zunächst wird der gesamte js
-Codeblock zunächst als Makroaufgabe ausgeführt und nacheinander 1、6、13
ausgegeben.
Nachdem die gesamte Codeblock-Makroaufgabe ausgeführt wurde, werden zwei Mikroaufgaben und eine Makroaufgabe generiert, sodass die Makroaufgabenwarteschlange eine Makroaufgabe und die Mikroaufgabenwarteschlange zwei Mikroaufgaben enthält.
Nachdem die Makroaufgabe ausgeführt wurde, werden alle von dieser Makroaufgabe generierten Mikroaufgaben ausgeführt. Es werden also 7、Promise.resolve、12
ausgegeben. Diese Mikrotask hat zwei weitere Makrotasks hervorgebracht, sodass die Makrotask-Warteschlange derzeit drei Makrotasks enthält.
Von den drei Makrotasks wird diejenige ohne festgelegte Verzögerung zuerst ausgeführt, sodass 8
ausgegeben wird. Diese Makrotask generiert keine Mikrotasks, sodass keine Mikrotasks ausgeführt werden müssen, und die nächste Makrotask wird weiterhin ausgeführt.
Verzögern Sie die Ausführung der Makrotask um 100
Millisekunden, geben Sie 9、10
aus und generieren Sie eine Mikrotask, sodass die Mikrotask-Warteschlange derzeit über eine Mikrotask verfügt.
Nachdem die Makrotask ausgeführt wurde, werden alle von der Makrotask generierten Mikrotasks ausgeführt Alle Mikrotasks in der Task-Warteschlange geben 11
aus.
Die Makrotask-Ausführung erfolgt 2、3、5
einer Verzögerung von 1000
Millisekunden. Daher verfügt die Mikrotask-Warteschlange derzeit über eine Mikrotask
. Die Makrotask wird ausgeführt. Alle generierten Mikrotasks führen alle Mikrotasks in der Mikrotask-Warteschlange aus und geben 4
aus.
Daher gibt das obige Codebeispiel 1, 6, 13, 7 1、6、13、7、Promise.resolve、12、8、9、10、11、2、3、5、4
aus 1、6、13、7、Promise.resolve、12、8、9、10、11、2、3、5、4
4, habt ihr es richtig gemacht?
Viele Freunde verstehen setTimeout(fn)
nicht. Ist es nicht offensichtlich, dass die Verzögerungszeit nicht sofort ausgeführt werden sollte?
Wir können setTimeout(fn)
als setTimeout(fn,0)
verstehen, was eigentlich dasselbe bedeutet.
Wir wissen, dass js in synchrone Aufgaben und asynchrone Aufgaben unterteilt ist. setTimeout(fn)
ist eine asynchrone Aufgabe. Auch wenn Sie hier keine Verzögerungszeit festlegen, wird sie in die asynchrone Warteschlange eingegeben und erst ausgeführt, wenn der Hauptthread vorhanden ist Leerlauf.
Der Autor wird es noch einmal erwähnen. Glauben Sie, dass die Verzögerungszeit, die wir nach setTimeout
festlegen, js
definitiv entsprechend unserer Verzögerungszeit ausgeführt wird? Die von uns festgelegte Zeit dient nur dazu, die Rückruffunktion auszuführen, aber ob der Hauptthread frei ist, ist eine andere Sache. Wir können ein einfaches Beispiel geben.
Funktion test5() { setTimeout(function () { console.log("setTimeout"); }, 100); sei i = 0; while (wahr) { i++; } } test5();
Gibt das obige Beispiel definitiv setTimeout
nach 100
Millisekunden aus? Nein, da unser Hauptthread in eine Endlosschleife eingetreten ist und keine Zeit hat, asynchrone Warteschlangenaufgaben auszuführen.
GUI渲染
wird hier erwähnt. Einige Freunde verstehen es möglicherweise nicht im Detail. Hier ist nur ein kurzes Verständnis.
Da sich JS引擎线程
und GUI渲染线程
gegenseitig ausschließen, startet der Browser GUI渲染线程
nach dem Ausführungsergebnis einer宏任务
und vor dem, damit宏任务
und DOM任务
ordnungsgemäß ablaufen können Ausführung der nächsten宏任务
, Rendern der Seite.
Daher ist die Beziehung zwischen Makroaufgaben, Mikroaufgaben und GUI-Rendering wie folgt:
Makroaufgabe -> Mikroaufgabe -> GUI-Rendering -> Makroaufgabe -> ...
[Empfehlung für zugehörige Video-Tutorials: Web-Frontend]
Das Obige ist Eine ausführliche Analyse von JavaScript. Weitere Informationen zum Ausführungskontext und Ausführungsmechanismus finden Sie in anderen verwandten Artikeln auf der chinesischen PHP-Website!