Ich habe einen sehr vagen Eindruck von JavaScript. Es ist Single-Threaded und asynchron. In diesem Artikel geht es hauptsächlich um die Funktionsweise von JavaScript. Aber vorher wollen wir zunächst diese Konzepte verstehen (jetzt lernen und jetzt verkaufen) .
Prozess ist die Einheit der Systemressourcenzuweisung und -planung. Ein laufendes Programm entspricht einem Prozess. Ein Prozess umfasst laufende Programme sowie die von den Programmen verwendeten Speicher- und Systemressourcen. Wenn es sich um eine Single-Core-CPU handelt, läuft gleichzeitig nur ein Prozess. Eine Single-Core-CPU kann jedoch auch mehrere Aufgaben gleichzeitig ausführen. Sie können beispielsweise die täglich empfohlenen Songs von NetEase Cloud Music anhören, während Sie einen Blog-Beitrag auf NetEase Youdao Cloud Notes schreiben. Dies zählt als zwei Prozesse (Multiprozess). Der laufende Mechanismus besteht darin, eine Zeit lang Lieder abzuspielen und eine Zeit lang auf Ihre Eingabe zu reagieren. Da die CPU-Umschaltgeschwindigkeit jedoch sehr hoch ist, ist dies überhaupt nicht zu spüren. sodass Sie denken, dass diese beiden Prozesse gleichzeitig laufen. Ressourcen werden zwischen Prozessen isoliert.
Was ist ein Thread? Ein Thread ist der Executor unter einem Prozess. Ein Prozess startet mindestens einen Thread (den Hauptthread) und kann auch mehrere Threads starten. NetEase Cloud Music spielt beispielsweise Audio ab und zeigt gleichzeitig Liedtexte an. Der Multiprozessvorgang wird tatsächlich über Threads im Prozess ausgeführt. Threads unter einem Prozess teilen sich Ressourcen. Wenn mehrere Threads gleichzeitig dieselbe Ressource betreiben, kommt es zu Ressourcenkonflikten. Das ist eine andere Frage.
Parallelität bezieht sich auf den laufenden Status eines Programms, bei dem mehrere Dinge gleichzeitig parallel verarbeitet werden. Da ein Thread nur eine Sache gleichzeitig verarbeiten kann, erfordert die Parallelität, dass mehrere Threads mehrere Dinge gleichzeitig ausführen.
Parallelität bezieht sich auf die Designstruktur eines Programms, sodass mehrere Dinge abwechselnd gleichzeitig verarbeitet werden können. Der Punkt ist, dass jeweils nur eine Sache ausgeführt wird. Beispielsweise kann eine Single-Core-CPU den Prozess der gleichzeitigen Ausführung mehrerer Aufgaben realisieren.
Synchronisation und Asynchronität beziehen sich auf das Verhalten des Programms. Synchron (synchron) bedeutet, dass das Programm bei einem Aufruf wartet, bis das Ergebnis zurückgegeben wird. Es wird erst dann zurückgegeben, wenn kein Ergebnis vorliegt. Mit anderen Worten liegt eine Synchronisierung vor, wenn der Anrufer aktiv auf den anrufenden Prozess wartet.
Asynchron bedeutet, unmittelbar nach dem Ausgeben eines Aufrufs zurückzukehren, das Ergebnis wird jedoch nicht sofort zurückgegeben. Der Anrufer muss nicht aktiv warten, wenn der Angerufene das Ergebnis erhält, wird er aktiv benachrichtigt.
Gehen Sie zum Beispiel in einen Milchteeladen, um Getränke zu kaufen. Synchronisierung bedeutet, dass ein Kunde einen Bedarf (Anfrage) angibt und dann darauf wartet, dass der Kellner das Getränk zubereitet. Der Kunde geht, nachdem er das bestellte Getränk erhalten hat, und der nächste Kunde wiederholt den oben genannten Vorgang. Asynchron bedeutet, dass sich die Kunden zuerst anstellen, um zu bestellen, und nach der Bestellung die Bestellung beiseite legen. Der Kellner ruft ihre Nummer an, wenn sie Sie anrufen, und Sie holen sie einfach ab.
Threads stehen also nicht in direktem Zusammenhang mit Synchronisation und Asynchronität, und ein einzelner Thread kann auch eine asynchrone Implementierung erreichen. Die Implementierungsmethode wird im Folgenden ausführlich erläutert.
Blockieren und Nicht-Blockieren beziehen sich auf den Wartezustand. Blockieren bedeutet, dass der Thread „angehalten“ wird, während der Aufruf wartet (CPU-Ressourcen werden an anderer Stelle zugewiesen).
Nicht blockierend (Nicht blockierend) bedeutet, dass sich die CPU-Ressourcen des Warteprozesses noch im Thread befinden und der Thread auch andere Dinge tun kann.
Nehmen Sie das Beispiel des Anstehens, um gerade Getränke zu kaufen. Blockieren bedeutet, dass Sie während des Wartens nichts tun können.
Die Synchronisierung kann also blockierend oder nicht blockierend sein, und die asynchrone Synchronisierung kann blockierend oder nicht blockierend sein.
Nachdem Sie die oben genannten Konzepte grob verstanden haben, werden Sie wissen, dass es keinen Widerspruch zwischen Single-Threading und Asynchronität gibt. Wie wird JS ausgeführt? JS ist eigentlich eine Sprache. Ob es sich um eine Single-Thread- oder Multi-Thread-Sprache handelt, hängt von der jeweiligen Betriebsumgebung ab. JS wird normalerweise im Browser ausgeführt und von der JS-Engine analysiert und ausgeführt. Schauen wir uns den Browser genauer an.
Die derzeit beliebtesten Browser sind: Chrome, IE, Safari, Firefox, Opera. Der Kern des Browsers ist Multi-Threaded. Ein Browser besteht normalerweise aus den folgenden residenten Threads:
Rendering-Engine-Thread: Wie der Name schon sagt, ist dieser Thread für das Rendern der Seite verantwortlich
JS Engine-Thread: Verantwortlich für das Parsen und Ausführen von JS
Timing-Trigger-Thread: Verarbeitung von Timing-Ereignissen wie setTimeout, setInterval
Ereignisauslöser-Thread: Verarbeitung von DOM-Ereignissen
Asynchroner HTTP-Anforderungsthread: Verarbeitung von HTTP-Anforderungen
Es ist zu beachten, dass der Rendering-Thread und der JS Engine-Thread kann nicht gleichzeitig verarbeitet werden. Wenn der Rendering-Thread Aufgaben ausführt, wird der JS-Engine-Thread angehalten. Da JS das DOM manipulieren kann, ist der Browser möglicherweise ratlos, wenn JS das DOM während des Renderns verarbeitet.
Wenn wir über Browser sprechen, sprechen wir normalerweise von zwei Engines: der Rendering-Engine und der JS-Engine. Die Rendering-Engine dient zum Rendern der Seite. Chrome/Safari/Opera verwenden die Webkit-Engine, IE verwendet die Trident-Engine und FireFox verwendet die Gecko-Engine. Verschiedene Engines implementieren denselben Stil inkonsistent, was zu dem oft kritisierten Problem der Browser-Stilkompatibilität führt. Wir werden hier nicht im Detail darauf eingehen.
Die JS-Engine kann als virtuelle JS-Maschine bezeichnet werden, die für das Parsen und Ausführen von JS-Code verantwortlich ist. Es umfasst normalerweise die folgenden Schritte:
Lexikalische Analyse: Zerlegen Sie den Quellcode in sinnvolle Wortsegmente
Syntaxanalyse: Verwenden Sie einen Syntaxanalysator. Parse die Wortsegmentierung in einen Syntaxbaum
Codegenerierung: Generieren Sie Code, den die Maschine ausführen kann
Codeausführung
Die JS-Engines verschiedener Browser sind ebenfalls unterschiedlich. Chrome verwendet V8, FireFox verwendet SpiderMonkey, Safari verwendet JavaScriptCore und IE verwendet Chakra.
Um auf die Aussage zurückzukommen, dass JS Single-Threaded ist: Im Wesentlichen öffnet der Browser nur einen JS-Engine-Thread, um JS zur Laufzeit zu analysieren und auszuführen. Warum also nur ein Motor? Wenn zwei Threads gleichzeitig das DOM betreiben, ist der Browser dann wieder ratlos? !
Nachdem wir so viel geredet haben, wollen wir endlich über den gesamten Laufprozess von JS sprechen.
Schauen wir uns zunächst an, wie der JS-synchrone Ausführungsprozess erreicht wird. Dies beinhaltet ein sehr wichtiges Konzept – den Ausführungskontext. Eine meiner Übersetzungen, Deep Learning JavaScript Closures, erklärt dieses Konzept ausführlich.
Der Ausführungskontext zeichnet die Umgebung auf, in der der Code ausgeführt wird. Im aktuellen Ausführungsstatus ist ein Ausführungskontext wirksam. Was genau wird also im Ausführungskontext erfasst? Es gibt wahrscheinlich eine lexikalische Umgebung, eine variable Umgebung usw. Um ein einfaches Beispiel zu geben:
var x = 10; function foo(){ var y=20; function bar(){ var z=15; } bar(); } foo();
Wenn der Code ausgeführt wird, tritt er zunächst in den globalen Kontext ein. Wenn dann foo()
ausgeführt wird, wird der foo-Kontext eingegeben. Natürlich ist der globale Kontext zu diesem Zeitpunkt noch vorhanden. Wenn bar()
ausgeführt wird, wird der Balkenkontext erneut eingegeben. Kehren Sie nach der Ausführung bar()
zum Foo-Kontext zurück. Kehren Sie nach der Ausführung von foo()
zum globalen Kontext zurück. Daher bildet der Ausführungskontext des Ausführungsprozesses einen Aufrufstapel (Aufrufstapel), zuerst rein, zuletzt raus.
// 进栈 3 bar Context => => 2 foo Context => 2 foo Context 1 global Context 1 global Context 1 global Context // 出栈 3 bar Context 2 foo Context => 2 foo Context => => 1 global Context 1 global Context 1 global Context
Während der JS-Ausführung ist nur ein Ausführungskontext wirksam. Da JS Single-Threaded ist, kann es jeweils nur eine Aufgabe ausführen.
Die oben genannten Prozesse werden alle synchron ausgeführt.
Sehen wir uns an, welche nativen asynchronen Ereignisse in JS vorkommen:
setTimeout
setInterval
Ereignis-Listener
Ajax-Anfrage
usw.
Der asynchrone Effekt von JS profitiert von der Ausführungsumgebung des Browsers. Tatsächlich öffnet der Browser einen weiteren Thread, um diese Stücklistenereignisse zu verarbeiten. Beispiel:
function foo(){ console.log(1); } function bar(){ console.log(2); } foo(); setTimeout(function cb(){ console.log(3); }); bar();
Gemäß der Analyse im vorherigen Abschnitt geben Sie zuerst den globalen Kontext ein, führen Sie ihn zu foo()
aus und geben Sie die foo-Kontextumgebung ein Die foo-Kontextumgebung wird aus dem Stapel entnommen, an console.log(1)
ausgeführt und an den geplanten Verarbeitungsthread des setTimeout
übergeben. und die Konsole gibt 2 aus; der Foo-Kontext wird angezeigt. Warten Sie, bis der Browser-Thread die Ausführung beendet hat, und geben Sie die bar()
-Rückruffunktion nach der Ausführung an die aktuelle console.log(2)
-Aufgabenwarteschlange zurück Wenn festgestellt wird, dass der Stapel leer ist, führt die JS-Engine des Browsers eine Schleife aus und entfernt den Kopf der Ereigniswarteschlange in den JS-Ausführungsstapel und die Konsole gibt 3 aus; die Ereigniswarteschlange ist leer und der globale Kontext wird aus dem Stapel entfernt. setTimeout
cb()
Das Obige ist der Ereignisschleifenmechanismus der JS-Engine, ein Mechanismus zur Erzielung einer asynchronen Implementierung. Es handelt sich hauptsächlich um Browser-Thread, Aufgabenwarteschlange und cb()
JS-Engineconsole.log(3)
. Daher können wir sehen, dass die asynchrone Anforderung von JS darauf angewiesen ist, dass der Browser seiner laufenden Umgebung das Ergebnis verarbeitet und zurückgibt. Darüber hinaus erklärt dies auch, warum das
verweist, da diese asynchronen Codes im globalen Kontext ausgeführt werden. Nachwort: Ich weiß nicht, ob ich es richtig verstanden habe und ich weiß nicht, ob ich es klar erklärt habe oder nicht. Wenn es Unangemessenheiten gibt, weisen Sie bitte darauf hin. Referenzmaterialien: this
window
JavaScript: Synchronisation, Asynchronität und Ereignisschleife (Ereignisschleife) gründlich verstehen
Ich frage mich immer noch, was Parallelität ist und Parallelität?
IMWeb Community Browser-Prozess? Faden? Blödsinn, ich kann den Unterschied nicht erkennen!
Eingehende Analyse von Javascript als Single-Threading
Eine kurze Einführung in JavaScript-Single-Threading und Browser-Ereignisschleife
AlloyTeam [Weiter zur Javascript-Reihe] Lassen Sie uns über das Ereignisschleifenmodell von setTimeout sprechen
Prinzipien der asynchronen JavaScript-Programmierung von Moustache Brother
Ruan Yifeng JavaScript läuft Detaillierte Erklärung des Mechanismus: Reden wir noch einmal über Event Loop
[Kommentar von Pu Ling] Detaillierte Erklärung des JavaScript-Betriebsmechanismus: Reden wir über Event Schleife
noch einmalPhilip Roberts: Hilfe, ich stecke in einer Ereignisschleife fest.
Philip Roberts: Was zum Teufel ist eigentlich die Ereignisschleife?
jquery中Ajax的异步和同步
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des JavaScript-Funktionsmechanismus und konzeptionelle Analyse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!