1. Die JavaScript-Engine ist Single-Threaded
Wie Sie dem folgenden Code entnehmen können, ist der erste Code, der setTimeout verwendet, eine Endlosschleife. Da es sich um einen einzelnen Thread handelt, haben die folgenden beiden Timer keine Chance zur Ausführung.
<script type="text/javascript"> setTimeout( function(){ while(true){} } , 100); setTimeout( function(){ alert('你好!setTimeout'); } , 200); setInterval( function(){ alert('你好!setInterval'); } , 200); </script>
Der Kernel des Browsers ist multithreaded. Sie arbeiten unter der Kontrolle des Kernels zusammen, um die Synchronisierung aufrechtzuerhalten. Ein Browser implementiert mindestens drei residente Threads: einen Thread für die Javascript-Engine, einen Thread für das GUI-Rendering und einen Thread zum Auslösen von Browserereignissen .
Die JavaScript-Engine basiert auf der ereignisgesteuerten Single-Thread-Ausführung. Die JS-Engine wartet auf das Eintreffen von Aufgaben in der Aufgabenwarteschlange und verarbeitet sie dann. Der Browser verfügt über jeweils nur einen JS-Thread, der das JS-Programm ausführt Zeit.
Der GUI-Rendering-Thread ist für das Rendern der Browseroberfläche verantwortlich. Dieser Thread wird ausgeführt, wenn die Schnittstelle neu gezeichnet werden muss (Repaint) oder wenn ein Reflow (Reflow) durch einen bestimmten Vorgang verursacht wird. Es ist jedoch zu beachten, dass sich der GUI-Rendering-Thread und die JS-Engine gegenseitig ausschließen. Wenn die JS-Engine ausgeführt wird, wird der GUI-Thread angehalten und GUI-Updates werden in einer Warteschlange gespeichert und sofort ausgeführt, wenn die JS-Engine ausgeführt wird Leerlauf.
Der Browser-Ereignis-Trigger-Thread Wenn ein Ereignis ausgelöst wird, fügt der Thread das Ereignis am Ende der ausstehenden Warteschlange hinzu und wartet auf die Verarbeitung durch die JS-Engine. Diese Ereignisse können aus dem Codeblock stammen, der derzeit von der JavaScript-Engine ausgeführt wird, z. B. setTimeOut, oder aus anderen Threads im Browserkernel, z. B. Mausklicks, asynchronen AJAX-Anforderungen usw. Aufgrund der Single-Thread-Beziehung von JS jedoch alle Diese Ereignisse müssen zur Verarbeitung durch die JS-Engine in die Warteschlange gestellt werden.
Wie aus dem Bild oben ersichtlich ist, ist die JavaScript-Engine im Browser ereignisgesteuert. Die Ereignisse können hier als verschiedene Aufgaben betrachtet werden, die ihr vom Browser zugewiesen wurden In der Aufgabenwarteschlange müssen diese Aufgaben aufgrund der Single-Thread-Beziehung nacheinander in die Warteschlange gestellt und von der Engine verarbeitet werden.
t1, t2....tn stellen unterschiedliche Zeitpunkte dar, und die entsprechenden kleinen Quadrate unter tn stellen die Aufgaben zu diesem Zeitpunkt dar.
t1-Zeit:
1. GUI-Rendering-Thread
2. Browser-Ereignis-Trigger-Thread:
Im Zeitraum t1 klickt der Benutzer zunächst auf eine Maustaste. Der Klick wird vom Browser-Ereignis-Trigger-Thread erfasst und bildet ein Mausklick-Ereignis. Wie aus der Abbildung ersichtlich ist, wird dieses Ereignis für den JavaScript-Engine-Thread asynchron übertragen Da die Engine die Aufgabe bei t1 verarbeitet, wartet dieses Mausklickereignis am Ende der Aufgabenwarteschlange auf die Verarbeitung.
3. Timing-Trigger-Thread:
Der Timing-Zähler des Browsermodells wird hier nicht von der JavaScript-Engine gezählt, da die JavaScript-Engine sich in einem blockierten Thread-Zustand befindet. Sie muss sich auf die Zeit verlassen und das Timing auslösen. Das Timing-Ereignis in der Warteschlange ist also ein asynchrones Ereignis.
4. Während dieses Zeitraums von t1, nachdem das Mausklickereignis ausgelöst wurde, kommt auch das zuvor festgelegte setTimeout-Timing an. Zu diesem Zeitpunkt generiert der Timing-Trigger-Thread ein asynchrones Timing-Ereignis und stellt es in die Aufgabenwarteschlange . Dieses Ereignis wird nach dem Rückruf des Klickereignisses in die Warteschlange gestellt und wartet auf die Verarbeitung. Auf die gleiche Weise wird als nächstes noch innerhalb der t1-Periode ein setInterval-Timer hinzugefügt. Da es sich um einen Intervall-Timer handelt, werden diese beiden Ereignisse innerhalb der t1-Periode in die Warteschlange gestellt verarbeitet werden.
5. Ajax asynchrone Anfrage:
Der Browser öffnet eine neue HTTP-Thread-Anfrage und wenn zuvor ein Rückruf festgelegt wurde, generiert der asynchrone Thread ein Statusänderungsereignis und stellt es in die Verarbeitungswarteschlange der JavaScript-Engine, um auf die Verarbeitung zu warten.
2. Die Ausführungsreihenfolge der Aufgaben ist unterschiedlich und auch die Anzeigeergebnisse sind unterschiedlich
1) Die setTimeout-Funktion wird nicht verwendet
Zur Veranschaulichung wird hier ein Codebeispiel aus dem Internet verwendet.
<a href="#" id="doBtn">do something</a> <div id="status"></div> <script type="text/javascript"> var doBtn = document.getElementById('doBtn') , status = document.getElementById('status'); function sleep(ms) { var start = new Date(); while (new Date() - start <= ms) {} } doBtn.onclick = function(e) { status.innerHTML = 'doing...please wait...'; sleep(3000); // 模拟一个耗时较长的计算过程,3s status.innerHTML = 'done'; return false; }; </script>
Ich habe den obigen Code in Firefox ausgeführt. Der Plan besteht darin, auf die Schaltfläche „etwas tun“ zu klicken, dann „Wird ausgeführt ... bitte warten ...“ anzuzeigen, dann den Ruhezustand auszuführen und schließlich „Fertig“ anzuzeigen.
Das Ergebnis ist jedoch, dass der Browser nach dem Klicken etwa 3 Sekunden lang hängen bleibt und schließlich direkt „Fertig“ anzeigt.
Aus der Analyse geht hervor, dass beim Festlegen von status.innerHTML der GUI-Rendering-Thread ausgeführt werden muss, der JavaScript-Engine-Thread jedoch weiterhin ausgeführt wird und sich der JavaScript-Engine-Thread und der GUI-Rendering-Thread gegenseitig ausschließen. also wird am Ende „fertig“ angezeigt.
2) Verwenden Sie die setTimeout-Funktion
<a href="#" id="doBtn2">do something timer</a> <div id="status2"></div> <script type="text/javascript"> var doBtn2 = document.getElementById('doBtn2') , status2 = document.getElementById('status2'); function sleep2(ms) { var start = new Date(); while (new Date() - start <= ms) {} } doBtn2.onclick = function(e) { status2.innerHTML = 'doing...please wait...'; setTimeout(function() { sleep2(3000); status2.innerHTML = 'done'; }, 100); return false; }; </script>
Fügen Sie nach „Doing…Please Wait…“ ein SetTimeout hinzu, um die Ausführung zu verzögern und dem Browser Zeit zum Rendern zu geben. Zu diesem Zeitpunkt wird „Doing…Please Wait…“ angezeigt. Führen Sie dann die Schlaffunktion aus und zeigen Sie schließlich „Fertig“ an.
Später stellten einige Internetnutzer fest, dass es in Firefox nicht funktionierte. Später habe ich den Code geändert und die Bindung von onclick in das window.onload-Ereignis eingefügt , , Ich werde den Skriptvorgang erneut ausführen.
<script type="text/javascript"> function sleep(ms) { //... } window.onload = function() { var doBtn = document.getElementById('doBtn'), status = document.getElementById('status'); var doBtn2 = document.getElementById('doBtn2') , status2 = document.getElementById('status2'); doBtn.onclick = function(e) { //... }; doBtn2.onclick = function(e) { //... }; }; </script>
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er wird für das Studium aller hilfreich sein.