JavaScripts setTimeout und setInterval sind zwei Methoden, die die Gefühle anderer Leute leicht täuschen können, weil wir oft denken, dass sie beim Aufruf auf eine vorgegebene Weise ausgeführt werden, wie zum Beispiel
[javascript]
setTimeout( function(){ Alert('Hello!'); } , 0);
setTimeout( function(){ Alert ('Hallo!'); } , 0);
setInterval( callbackFunction , 100);
Ich denke, die Begrüßungsmethode in setTimeout wird sofort ausgeführt, da dies nicht ausgesagt wird dünn, aber das JavaScript-API-Dokument definiert die Bedeutung des zweiten Parameters eindeutig als die Anzahl der Millisekunden, nach denen die Rückrufmethode ausgeführt wird. Wenn er auf 0 Millisekunden gesetzt ist, wird er natürlich sofort ausgeführt , die callbackFunction-Methode von setInterval wird jedes Mal ausgeführt. Ich habe keinen Zweifel daran, dass sie sofort nach einem Intervall von 100 Millisekunden ausgeführt wird!
Aber wenn Ihre Erfahrung in der Entwicklung von JavaScript-Anwendungen weiter zunimmt und bereichert, werden Sie eines Tages Finden Sie einen seltsamen Code und Sie sind verwirrt:
[javascript]
div.onclick = function(){
setTimeout( function(){document .getElementById('inputField').focus();}, 0 );
div.onclick = function(){
setTimeout( function(){document.getElementById('inputField') .focus();}, 0);
};
Da es nach 0 Millisekunden ausgeführt wird, warum sollte man setTimeout in diesem Moment verwenden? >
setTimeout( function(){ while(true){} } , 100); 🎜>setTimeout( function(){ Alert('Hello!' ); } , 200);
setInterval( callbackFunction , 200);setTimeout( function(){ while(true){} } , 100) ;
setTimeout( function(){ alarm('you OK!'); } , 200);
setInterval( callbackFunction , 200);
Die erste Zeile von Code tritt in eine Endlosschleife ein, aber Sie werden bald feststellen, dass die zweite und dritte Zeile nicht Ihren Erwartungen entspricht, die Alarmbegrüßung nicht angezeigt wurde und es keine Neuigkeiten von callbacKFunction gab.
Das Folgende ist eine kurze Erklärung basierend auf der Browser-Kernel-Verarbeitungsmethode.
Durchsuchen Die Browser-Kernel-Implementierung ermöglicht die asynchrone Ausführung dieser Threads unter Kernel-Steuerung, um die Synchronisierung aufrechtzuerhalten Eine Browser-Kernel-Implementierung verfügt über mindestens drei residente Threads: JavaScript-Engine-Thread, Schnittstellen-Rendering-Thread und Browser-Ereignisauslösung. Zusätzlich zu Threads gibt es auch einige Threads, die nach der Ausführung beendet werden, z. B. HTTP-Anforderungsthreads asynchrone Ereignisse. Das folgende Diagramm veranschaulicht, wie die Single-Threaded-JavaScript-Engine mit anderen Threads interagiert und kommuniziert. Obwohl die Implementierungsdetails jedes Browserkernels unterschiedlich sind, sind die Aufrufprinzipien ähnlich >JavaScripts setTimeout und setInterval sind zwei Methoden, die die Gefühle anderer leicht täuschen können, weil Wir denken oft, dass es auf die etablierte Weise ausgeführt wird, zum Beispiel
Wie aus dem Bild ersichtlich ist, ist die JavaScript-Engine ereignisgesteuert. Die Ereignisse können hier als verschiedene Aufgaben angesehen werden, die ihr vom Browser zugewiesen werden stammen aus dem Codeblock, der aktuell von der JavaScript-Engine ausgeführt wird, z. B. dem Aufruf von setTimeout zum Hinzufügen einer Aufgabe, oder aus dem Browser. Andere Threads des Kernels, z. B. Mausklickereignisse von Schnittstellenelementen, Benachrichtigungen zur geplanten Triggerzeit und asynchrone Änderung des Anforderungsstatus Benachrichtigungen usw. Aus Code-Sicht sind Aufgabenentitäten verschiedene Rückruffunktionen, und die JavaScript-Engine wartet auf das Eintreffen von Aufgaben in der Aufgabenwarteschlange. Aufgrund der Single-Thread-Beziehung müssen diese Aufgaben in die Warteschlange gestellt und verarbeitet werden durch den Motor nacheinander.
Die obige Abbildung t1-t2..tn stellt verschiedene Zeitpunkte dar, und die entsprechenden kleinen Quadrate unter tn stellen die Zeitpunkte dar. Vorausgesetzt, es ist der Zeitpunkt t1, ist der Motor Lassen Sie uns zu diesem Zeitpunkt den Status anderer Threads im Browserkernel beschreiben.
T1-Zeit:
GUI-Rendering-Thread:
Dieser Thread ist für das Rendern der HTML-Elemente der Browseroberfläche verantwortlich oder wenn durch einen Vorgang ein Reflow verursacht wird. Dieser Thread konzentriert sich jedoch auf die Erläuterung JavaScript-Timing-Mechanismus: Zu diesem Zeitpunkt muss über den Rendering-Thread gesprochen werden, da dieser Thread sich gegenseitig mit dem JavaScript-Engine-Thread ausschließt. Dies ist leicht zu verstehen, da JavaScript-Skripte DOM-Elemente manipulieren können, wenn sie die Eigenschaften dieser Elemente ändern Beim gleichzeitigen Rendern der Schnittstelle sind die vor und nach dem Rendering-Thread erhaltenen Elementdaten möglicherweise inkonsistent.
Während die JavaScript-Engine das Skript ausführt, befindet sich der Browser-Rendering-Thread in einem angehaltenen Zustand. Das bedeutet, dass es „eingefroren“ ist.
Führen Sie es also im Skript aus. Aktualisierungen der Schnittstelle, wie das Hinzufügen von Knoten, das Löschen von Knoten oder das Ändern des Erscheinungsbilds von Knoten, werden nicht sofort widergespiegelt werden in einer Warteschlange gespeichert und können gerendert werden, wenn die JavaScript-Engine inaktiv ist.
GUI-Ereignis-auslösender Thread:
Die Ausführung des JavaScript-Skripts hat keinen Einfluss auf die Auslösung des HTML-Elements Im Zeitraum t1 klickt der Benutzer zunächst auf eine Maustaste und der Klick wird durch den Browser-Ereignisthread ausgelöst. Nach der Erfassung wird ein Mausklickereignis für den JavaScript-Engine-Thread gebildet. Dieses Ereignis wird von anderen Threads asynchron an das Ende der Aufgabenwarteschlange übertragen. Da die Engine die Aufgabe bei t1 verarbeitet, wartet dieses Mausklickereignis auf die Verarbeitung
Timing-Trigger-Thread:
Beachten Sie, dass der Timing-Zähler des Browsermodells hier nicht von der JavaScript-Engine gezählt wird, da die JavaScript-Engine Single-Threaded ist und nicht zählen kann, wenn sie sich in einem blockierten Thread-Zustand befindet. Sie muss sich auf die Zeit und das Trigger-Timing von außen verlassen. Daher sind die geplanten Ereignisse in der Warteschlange auch asynchrone Ereignisse.
Wie aus der Abbildung hervorgeht, ist in diesem t1-Zeitraum nach dem Auslösen des Mausklickereignisses auch das zuvor festgelegte setTimeout Das Timing ist angekommen. In diesem Moment generiert der Timing-Trigger-Thread ein asynchrones Timing-Ereignis und stellt es in die Aufgabenwarteschlange. Das Ereignis wird nach dem Klickereignis-Rückruf in die Warteschlange gestellt und wartet auf die Verarbeitung Während des Zeitraums wurde auch ein bestimmter setInterval-Timer hinzugefügt, der während des t1-Zeitraums zweimal nacheinander ausgelöst wurde. Diese beiden Ereignisse wurden zur Verarbeitung in die Warteschlange gestellt > Es ist ersichtlich, dass, wenn der Zeitraum t1 sehr lang ist, viel größer als das Zeitintervall von setInterval, der Timing-Trigger-Thread kontinuierlich asynchrone Timing-Ereignisse generiert und diese an das Ende der Aufgabenwarteschlange stellt, unabhängig davon, ob dies der Fall ist oder nicht verarbeitet, aber sobald t1 und die ersten Aufgaben vor dem geplanten Ereignis verarbeitet wurden, werden die geplanten Ereignisse in diesen Anordnungen nacheinander ohne Unterbrechung ausgeführt. Dies liegt daran, dass für die JavaScript-Engine jede Aufgabe in der Die Verarbeitungswarteschlange wird auf die gleiche Weise verarbeitet.
[javascript]
setTimeout(function(){ /* Codeblock... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/*Code block... */
}, 10);
setTimeout(function( ){
/* Code block... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/ *Code block... */
Tatsächlich ist die Anfrage tatsächlich asynchron, aber Diese Anfrage Der Browser öffnet eine neue Thread-Anfrage (siehe Abbildung oben). Wenn zuvor ein Rückruf festgelegt wurde, generiert der asynchrone Thread ein Statusänderungsereignis und stellt es in die Verarbeitungswarteschlange der JavaScript-Engine Wenn die Aufgabe verarbeitet wird, führt die JavaScript-Engine die Rückruffunktion immer in einem einzelnen Thread aus, insbesondere wird die von onreadystatechange festgelegte Funktion in einem einzelnen Thread ausgeführt