Dieser Artikel vermittelt Ihnen relevantes Wissen über Javascript. Er stellt hauptsächlich Probleme im Zusammenhang mit dem Funktionsmechanismus und den Prinzipien von JavaScript vor, einschließlich Parsing-Engines und anderen Inhalten. Ich hoffe, dass er für alle hilfreich ist.
[Verwandte Empfehlungen: Javascript-Video-Tutorial, Web-Frontend]
Ich schreibe seit mehr als zwei Jahren JS und habe seinen Funktionsmechanismus und seine Prinzipien nie verstanden Zusammenfassend sind die Theorien und Prinzipien der Meister aufgeführt die Codeausführung.
Allerdings ist es jetzt schwierig zu definieren, ob die JavaScript-Engine ein Interpreter oder ein Compiler ist, da beispielsweise V8 (die JS-Engine von Chrome) tatsächlich, um die Laufleistung von JS zu verbessern, JS zunächst in native kompiliert Maschinencode erstellen und dann den Maschinencode ausführen (das ist viel schneller).
Welche Beziehung besteht zwischen der JavaScript-Parsing-Engine und ECMAScript?
Die JavaScript-Engine ist ein Programm, und der von uns geschriebene JavaScript-Code ist auch ein Programm. Dafür müssen Regeln definiert werden. Beispielsweise bedeutet die zuvor erwähnte Variable a = 1 + 1;:
Die Variable links stellt eine Deklaration dar, die die Variable a deklariert Das Gleichheitszeichen zeigt an, dass es sich um eine Zuweisungsanweisung handelt. Das letzte Semikolon gibt das Ende dieser Anweisung an. Mit ihnen gibt es einen Standard für die Messung. Die JavaScript-Engine kann den JavaScript-Code gemäß diesem Standard analysieren. Dann definiert das ECMAScript hier diese Regeln. Darunter definiert das Dokument ECMAScript 262 einen vollständigen Satz von Standards für die JavaScript-Sprache. Dazu gehören:
Zählen als Zahl, Zählen als String usw.
Definieren Sie den Operator ( +, -, >, Definiert die Syntax von JavaScript.
Welche Beziehung besteht zwischen der JavaScript-Parsing-Engine und dem Browser?
Einfach ausgedrückt ist die JavaScript-Engine eine der Komponenten des Browsers. Weil der Browser viele andere Dinge tun muss, wie z. B. das Parsen von Seiten, das Rendern von Seiten, die Cookie-Verwaltung, Verlaufsaufzeichnungen usw. Nun, da es sich um eine Komponente handelt, werden JavaScript-Engines im Allgemeinen von Browserentwicklern selbst entwickelt. Zum Beispiel: Chakra von IE9, TraceMonkey von Firefox, V8 von Chrome usw.
Es ist auch zu erkennen, dass verschiedene Browser unterschiedliche JavaScript-Engines verwenden. Wir können also nur sagen, welche JavaScript-Engine wir besser verstehen sollten.
Warum JavaScript Single-Threaded ist
Ein Hauptmerkmal der JavaScript-Sprache ist, dass sie Single-Threaded ist, das heißt, sie kann jeweils nur eine Sache ausführen. Warum kann JavaScript also nicht mehrere Threads haben? Dadurch kann die Effizienz verbessert werden.
Um Komplexität zu vermeiden, ist JavaScript seit seiner Geburt Single-Threaded. Dies ist zum Kernmerkmal dieser Sprache geworden und wird sich auch in Zukunft nicht ändern.
Um die Rechenleistung von Multi-Core-CPUs zu nutzen, schlägt HTML5 den Web Worker-Standard vor, der es JavaScript-Skripten ermöglicht, mehrere Threads zu erstellen, die untergeordneten Threads werden jedoch vollständig vom Haupt-Thread gesteuert und dürfen das DOM nicht bedienen . Daher ändert dieser neue Standard nichts an der Single-Threaded-Natur von JavaScript.
Ein Prozess ist die kleinste Einheit der CPU-Ressourcenzuweisung und ein Prozess kann mehrere Threads enthalten. Browser sind Multiprozess-Browser und jedes geöffnete Browserfenster ist ein Prozess.
Thread ist die kleinste Einheit der CPU-Planung. Der Speicherplatz des Programms wird von Threads im selben Prozess gemeinsam genutzt.
Sie können sich den Prozess wie ein Lager vorstellen, und der Thread ist ein LKW, der transportiert werden kann. Jedes Lager verfügt über mehrere eigene LKWs, die das Lager bedienen (jedes Lager kann von mehreren Fahrzeugen gleichzeitig gezogen werden). Zeit, aber jedes Lager kann gleichzeitig Waren transportieren. Ein Fahrzeug kann jeweils nur eine Aufgabe erfüllen, nämlich diese Fracht zu transportieren.
Kernpunkt:
Ein Prozess ist die kleinste Einheit der CPU-Ressourcenzuweisung (die kleinste Einheit, die Ressourcen besitzen und unabhängig laufen kann)
Thread ist die kleinste Einheit der CPU-Planung (ein Thread ist ein Programm, das auf a Prozess) Laufende Einheit, es können mehrere Threads in einem Prozess sein)
Verschiedene Prozesse können auch kommunizieren, aber die Kosten sind höher.
Browser sind Multiprozess-Browser
Nachdem wir den Unterschied zwischen Prozessen und Threads verstanden haben, wollen wir uns ein gewisses Verständnis von Browsern verschaffen: (Sehen wir uns zunächst das vereinfachte Verständnis an)
Der Grund, warum Browser ausgeführt werden können weil das System seinem Prozess Ressourcen (CPU, Speicher) zuweist. Vereinfacht ausgedrückt entspricht dies jedes Mal, wenn eine Registerkarte geöffnet wird, dem Erstellen eines unabhängigen Browserprozesses.
Nehmen Sie Chrome als Beispiel, und Sie können mehrere Prozesse im Task-Manager von Chrome sehen (jede Tab-Seite hat einen unabhängigen Prozess und einen Hauptprozess, der auch im Task-Manager angezeigt wird). .
Hinweis: Der Browser sollte auch hier über einen eigenen Optimierungsmechanismus verfügen. Nach dem Öffnen mehrerer Tab-Seiten können Sie im Chrome Task-Manager sehen, dass einige Prozesse zusammengeführt werden (also muss nicht jede Tab-Beschriftung einem Prozess entsprechen). Seien Sie absolut)
Welche Prozesse enthält der Browser?
( 1) Browserprozess: Es gibt nur einen Hauptprozess des Browsers (verantwortlich für Koordination und Steuerung). Rolle:
Verantwortlich für die Anzeige der Browseroberfläche und Benutzerinteraktion. Wie vorwärts, rückwärts usw. (4) Browser-Rendering-Prozess (Browser-Kernel, Renderer-Prozess, intern multithreaded): Standardmäßig verfügt jede Tab-Seite über einen Prozess und beeinflusst sich nicht gegenseitig. Die Hauptfunktionen sind: Seitenrendering, Skriptausführung, Ereignisverarbeitung usw.
Speicher verbessern: Das Öffnen einer Webseite im Browser entspricht dem Starten eines neuen Prozesses (der Prozess verfügt über eigene Multithreads)
Natürlich Der Browser führt manchmal mehrere Prozesse zusammen (z. B. werden Sie nach dem Öffnen mehrerer leerer Registerkarten feststellen, dass mehrere leere Registerkarten zu einem Prozess zusammengeführt wurden)
Vorteile von Browsern mit mehreren Prozessen
Wenn der Browser ein einzelner Prozess ist, wirkt sich der Absturz einer bestimmten Registerkarte auf den gesamten Browser aus. Wie schlecht wird die Erfahrung sein? Handelt es sich um einen einzelnen Prozess, wirkt sich der Absturz des Plug-Ins auch auf den gesamten Browser aus.
Natürlich wird auch der Speicher- und andere Ressourcenverbrauch größer sein, was bedeutet, dass Raum gegen Zeit getauscht wird. Egal wie groß der Speicher ist, er reicht für Chrome nicht aus. Das Problem des Speicherverlusts ist nur eine Verbesserung und wird auch zu einem erhöhten Stromverbrauch führen.
Browser-Kernel (Rendering-Prozess)
Es versteht sich, dass das Rendern der Seite, die Ausführung von JS und die Ereignisschleife alle innerhalb dieses Prozesses ausgeführt werden. Konzentrieren Sie sich als Nächstes auf die Analyse dieses Prozesses.
Bitte beachten Sie, dass der Rendering-Prozess des Browsers multithreaded ist (die JS-Engine ist Single-Threaded).Schauen wir uns dann an, welche Threads er enthält (listen Sie einige Hauptresidenten auf). Threads ):
Dabei sollten Sie zunächst ein gewisses Verständnis für die Prozesse und Threads im Browser haben. Lassen Sie uns dann über den Browser des Browsers sprechen Sobald Sie verstanden haben, wie der Prozess (Steuerungsprozess) mit dem Kernel kommuniziert, können Sie diesen Teil des Wissens miteinander verbinden, um ein vollständiges Konzept von Anfang bis Ende zu erhalten.
Wenn Sie den Task-Manager öffnen und dann einen Browser öffnen, können Sie Folgendes sehen: Im Task-Manager werden zwei Prozesse angezeigt (einer ist der Hauptsteuerungsprozess und der andere ist der Renderprozess, der die Tab-Seite öffnet) und dann hier Schauen wir uns unter der Prämisse den gesamten Prozess an: (Es ist stark vereinfacht)
An diesem Punkt haben wir ein Gesamtkonzept für die Funktionsweise des Browsers. Als nächstes klären wir einfach einige Konzepte
Da JavaScript das DOM manipulieren kann, ändern Sie die Attribute dieser Elemente und rendern gleichzeitig die Schnittstelle (dh der JS-Thread und der UI-Thread werden ausgeführt). gleichzeitig), dann können die vor und nach dem Rendering-Thread erhaltenen Elementdaten inkonsistent sein.
Um unerwartete Rendering-Ergebnisse zu verhindern, stellt der Browser eine sich gegenseitig ausschließende Beziehung zwischen dem GUI-Rendering-Thread und der JS-Engine ein. Wenn die JS-Engine ausgeführt wird, wird der GUI-Thread angehalten und GUI-Updates werden gespeichert eine Warteschlange, bis der JS-Engine-Thread sofort ausgeführt wird, wenn er inaktiv ist.
Aus der oben genannten sich gegenseitig ausschließenden Beziehung kann abgeleitet werden, dass JS die Seite blockiert, wenn die Ausführung zu lange dauert.
Angenommen, die JS-Engine führt beispielsweise eine große Menge an Berechnungen durch, selbst wenn die GUI zu diesem Zeitpunkt aktualisiert wird, werden sie in der Warteschlange gespeichert und warten auf die Ausführung, wenn die JS-Engine inaktiv ist. Dann wird die JS-Engine aufgrund der großen Menge an Berechnungen wahrscheinlich sehr lange im Leerlauf sein und sich natürlich extrem riesig anfühlen.
Versuchen Sie also zu vermeiden, dass die JS-Ausführung zu lange dauert, da dies zu einer inkonsistenten Darstellung der Seite führt und den Eindruck entstehen lässt, dass die Darstellung und das Laden der Seite blockiert sind.
Um dieses Problem zu lösen, zusätzlich zur Platzierung der Berechnung im Backend, wenn dies nicht vermieden werden kann und die große Berechnung mit der Benutzeroberfläche zusammenhängt, besteht meine Idee darin, setTimeout zu verwenden, um die Aufgabe aufzuteilen und etwas freie Zeit im Backend zu schaffen Mitte für die JS-Engine Gehen Sie und kümmern Sie sich um die Benutzeroberfläche, damit die Seite nicht direkt hängen bleibt.
Wenn Sie sich direkt für die mindestens erforderliche HTML5+-Version entscheiden, können Sie sich unten den WebWorker ansehen.
Wie im vorherigen Artikel erwähnt, ist die JS-Engine Single-Threaded, und wenn die JS-Ausführungszeit zu lang ist, wird die Seite blockiert. Ist JS also wirklich machtlos? gegen CPU-intensive Berechnungen?
So wurden Web Worker später in HTML5 unterstützt. Die offizielle Erklärung von
MDN lautet:
Web Worker bietet eine einfache Möglichkeit, Skripte in einem Hintergrundthread für Webinhalte auszuführen.
Threads können Aufgaben ausführen, ohne die Benutzeroberfläche zu beeinträchtigen. Ein Worker ist ein Objekt, das mit einem Konstruktor (Worker()) erstellt wurde, der eine benannte JavaScript-Datei ausführt (diese Datei enthält den Code, der im Worker-Thread ausgeführt wird).
Worker werden in einem anderen globalen Kontext ausgeführt, der sich vom aktuellen Fenster unterscheidet.
Daher führt die Verwendung der Fensterverknüpfung zum Abrufen des aktuellen globalen Bereichs (anstelle von „self“) zu einem Fehler innerhalb eines Workers Untergeordneter Thread (untergeordneter Thread) Wird vom Browser geöffnet, vollständig vom Hauptthread gesteuert und kann das DOM nicht bedienen)
Der JS-Engine-Thread und der Arbeitsthread kommunizieren auf bestimmte Weise (PostMessage-API, für deren Interaktion Serialisierungsobjekte erforderlich sind).Wenn es also sehr zeitaufwändige Arbeiten gibt, öffnen Sie bitte einen separaten Worker-Thread, damit der Hauptthread der JS-Engine nicht beeinträchtigt wird, egal wie weltbewegend er ist Das Ergebnis muss berechnet und dem Hauptthread mitgeteilt werden.
Und beachten Sie, dass die JS-Engine im Wesentlichen nicht als vom Browser geöffnetes Plug-in verstanden werden kann für die JS-Engine, die speziell zur Lösung umfangreicher Rechenprobleme verwendet wird.
Andere: Die detaillierte Erklärung von Worker würde den Rahmen dieses Artikels sprengen, daher werde ich nicht auf Details eingehen. WebWorker und SharedWorker ) Kernel-Prozess)-Freigabe
SharedWorker wird von allen Seiten des Browsers gemeinsam genutzt und kann nicht auf die gleiche Weise wie Worker implementiert werden, da es nicht mit einem Render-Prozess verbunden ist und von mehreren Render-Prozessen gemeinsam genutzt werden kann.
Daher erstellt der Chrome-Browser einen separaten Prozess für SharedWorker Für JavaScript-Programme gibt es nur einen SharedWorker-Prozess für jedes gleiche JavaScript im Browser, unabhängig davon, wie oft es erstellt wird.Wenn man das sieht, sollte es leicht verständlich sein, dass es sich um den Unterschied zwischen Prozessen und Threads handelt. SharedWorker wird von einem unabhängigen Prozess verwaltet, und WebWorker ist nur ein Thread unter dem Render-Prozess.
Um das Verständnis zu vereinfachen, wird die Vorarbeit direkt weggelassen:
Der Browser gibt die URL ein, der Browser-Hauptprozess übernimmt, öffnet einen Download-Thread, und dann Stellen Sie eine http-Anfrage (ohne DNS-Abfrage, IP-Adressierung usw.), warten Sie dann auf die Antwort, rufen Sie den Inhalt ab und übertragen Sie den Inhalt dann über die RendererHost-Schnittstelle an den Renderer-Prozess
Der Browser-Rendering-Prozess beginnt
Nach dem Der Browserkernel erhält den Inhalt. Das Rendern kann grob in die folgenden Schritte unterteilt werden:
HTML analysieren und DOM-Baum erstellen
CSS analysieren und Renderbaum erstellen (CSS-Code in eine baumförmige Datenstruktur analysieren und dann mit DOM kombinieren, um ihn in den Renderbaum zusammenzuführen)
Layout des Renderbaums (Layout/Reflow), verantwortlich für die Berechnung die Größe und Position jedes Elements
Zeichnen Sie den Renderbaum (Farbe) und zeichnen Sie die Seitenpixelinformationen
Der Browser sendet die Informationen jeder Ebene an die GPU, und die GPU setzt jede Ebene zusammen und zeigt sie auf dem Bildschirm an.
Alle detaillierten Schritte wurden weggelassen. Nach Abschluss des Renderns erfolgt das Ladeereignis und dann Ihre eigene JS-Logikverarbeitung.
Da einige detaillierte Schritte weggelassen wurden, möchte ich einige Details erwähnen, die möglicherweise Aufmerksamkeit erfordern.
Wie oben erwähnt, wird das Ladeereignis ausgelöst, nachdem das Rendern abgeschlossen ist. Können Sie also die Reihenfolge des Ladeereignisses und des DOMContentLoaded-Ereignisses unterscheiden?
Es ist ganz einfach, kennen Sie einfach ihre Definitionen:
Wenn das DOMContentLoaded-Ereignis ausgelöst wird, nur, wenn das DOM geladen ist, ausgenommen Stylesheets, Bilder, asynchrone Skripte usw.
Wenn das Onload-Ereignis ausgelöst wird, wurden alle DOM, Stylesheets, Skripte und Bilder auf der Seite geladen, das heißt, sie wurden gerendert. Die Reihenfolge lautet also: DOMContentLoaded ->Will CSS-Ladeblock der Dom-Baum? Rendering
Das Laden von CSS blockiert nicht das Parsen des DOM-Baums (DOM wird beim asynchronen Laden wie gewohnt erstellt)
Elemente wie Video, Iframe, Canvas, Webgl usw.
Andere, wie z. B. das bisherige Flash-Plug- im Der Unterschied zwischen Absolut- und Hardwarebeschleunigung
Es ist ersichtlich, dass Absolut zwar vom normalen Dokumentenfluss, jedoch nicht von der Standard-Verbundschicht getrennt werden kann. Selbst wenn sich die absoluten Informationen ändern, ändert sich dadurch der Renderbaum im normalen Dokumentfluss nicht. Wenn der Browser jedoch schließlich zeichnet, wird die gesamte zusammengesetzte Ebene gezeichnet, sodass sich Änderungen der absoluten Informationen weiterhin auf die Zeichnung auswirken der gesamten Verbundschicht. (Der Browser zeichnet es neu. Wenn die zusammengesetzte Ebene viel Inhalt enthält, ändern sich die von absolute eingebrachten Zeichnungsinformationen zu stark und der Ressourcenverbrauch ist sehr hoch.)
Und die Hardwarebeschleunigung erfolgt direkt in einer anderen zusammengesetzten Ebene Ebene (beginnend bei Null), daher wirken sich ihre Informationsänderungen nicht auf die Standard-Verbundebene aus (natürlich wirkt sie sich definitiv intern auf ihre eigene Verbundebene aus), sondern lösen nur die endgültige Komposition (Ausgabeansicht) aus
Im Allgemeinen wird ein Element nach der Aktivierung der Hardwarebeschleunigung zu einer zusammengesetzten Ebene, die vom normalen Dokumentfluss unabhängig sein kann. Nach der Änderung kann das Neuzeichnen der gesamten Seite vermieden und die Leistung verbessert werden Versuchen Sie, keine großen Mengen zusammengesetzter Ebenen zu verwenden, da die Seite sonst aufgrund des übermäßigen Ressourcenverbrauchs verzögert wird Standardmäßig wird die zusammengesetzte Ebene für nachfolgende Elemente gerendert das gleiche und haben die gleichen relativen oder absoluten Attribute), es wird standardmäßig zu einem zusammengesetzten Layer-Rendering. Wenn es nicht richtig gehandhabt wird, wird es die Leistung stark beeinträchtigen. Um es einfach zu verstehen, kann es tatsächlich als implizit betrachtet werden Synthesekonzept: Wenn a eine zusammengesetzte Schicht ist und b über a liegt, wird b auch implizit in eine zusammengesetzte Schicht umgewandelt, was besondere Aufmerksamkeit erfordert.
Sprechen Sie über den Betriebsmechanismus von JS von EventLoopBis zu diesem Punkt erfolgt bereits nach dem ersten Rendern der Browserseite eine Analyse des Betriebsmechanismus der JS-Engine.
Beachten Sie, dass wir nicht über Konzepte wie ausführbaren Kontext, VO, Scop-Kette usw. sprechen (diese können in einem anderen Artikel organisiert werden). Hier sprechen wir hauptsächlich darüber, wie JS-Code in Verbindung mit Event Loop ausgeführt wird.
Dann Ein Konzept verstehen:
Nachdem der Code im Stapel ausgeführt wurde, werden die Ereignisse in der Ereigniswarteschlange gelesen, um diese Rückrufe auszuführen, und so weiter
Beachten Sie, dass Sie immer auf den Stapel warten müssen. Die Ereignisse in der Ereigniswarteschlange werden erst gelesen, nachdem der Code ausgeführt wurde.
Wird es von der JS-Engine erkannt? Natürlich nicht. Es wird vom Timer-Thread gesteuert (da die JS-Engine selbst zu beschäftigt ist und keine Zeit hat, etwas anderes zu tun)
Wann wird der Timer-Thread verwendet? Bei Verwendung von setTimeout oder setInterval muss der Timer-Thread eine Zeitmessung durchführen. Nach Ablauf der Zeit wird das spezifische Ereignis in die Ereigniswarteschlange verschoben.
setTimeout anstelle von setInterval
Es gibt einen Unterschied zwischen der Verwendung von setTimeout zum Simulieren eines regulären Timings und der direkten Verwendung von setInterval.
Denn jedes Mal, wenn setTimeout ausgeführt wird, wird setTimeout nach einer gewissen Zeit ausgeführt. In der Mitte treten Fehler auf (der Fehler hängt mit der Codeausführungszeit zusammen)
Und setInterval ist Jedes Mal, wenn ein Ereignis für einen bestimmten Zeitraum verschoben wird, ist die tatsächliche Ausführungszeit möglicherweise nicht genau. Es ist auch möglich, dass das nächste Ereignis eintritt, bevor das Ereignis abgeschlossen ist.
Kumulativer Effekt: Wenn die Ausführung des setInterval-Codes vor dem erneuten Hinzufügen zur Warteschlange noch nicht abgeschlossen ist, führt dies dazu, dass der Timer-Code mehrmals hintereinander ohne Intervall ausgeführt wird. Selbst wenn sie in normalen Intervallen ausgeführt werden, kann die Ausführungszeit mehrerer setInterval-Codes kürzer als erwartet sein (da die Codeausführung eine gewisse Zeit in Anspruch nimmt. Browser wie iOS Webview oder Safari verfügen beispielsweise über eine Funktion, die dies nicht tut). Beim Scrollen ausführen. Wenn Sie setInterval verwenden, werden Sie feststellen, dass es nach Abschluss des Scrollens mehrmals ausgeführt wird. Da beim Scrollen der JS-Akkumulationsrückruf nicht ausgeführt wird, wird dies der Fall sein Dies führt zu festgefahrenen Problemen und einigen unbekannten Fehlern im Container (dieser Abschnitt wird später hinzugefügt, da setInterval über eine eigene Optimierung verfügt und keine wiederholten Rückrufe hinzufügt).
Und wenn der Browser minimiert und angezeigt wird, führt setInterval das Programm nicht aus stellt die Rückruffunktion von setInterval in die Warteschlange und wartet darauf, dass der Browser beim erneuten Öffnen des Fensters alles sofort ausführt
Angesichts so vieler Probleme wird derzeit allgemein davon ausgegangen, dass die beste Lösung ist: Verwenden Sie setTimeout, um setInterval zu simulieren, oder verwenden Sie bei besonderen Anlässen direkt requestAnimationFrame.
console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('script end');
script start script end promise1 promise2 setTimeout
(2) Alle Mikrotasks in der Mikrotask werden hinzugefügt. Gehen Sie zur Mikrotask-Warteschlange (Jobwarteschlangen) und warten Sie, bis die aktuelle Makroaufgabe ausgeführt wird, nachdem sie ausgeführt wurde. Diese Warteschlange wird vom JS-Engine-Thread verwaltet (dies basiert auf meinem eigenen Verständnis und meinen eigenen Spekulationen, da sie nahtlos unter dem Hauptthread ausgeführt wird)
Also , um den Betriebsmechanismus zusammenzufassen:Führen Sie eine Makroaufgabe aus (wenn sie sich nicht auf dem Stapel befindet, holen Sie sie aus der Ereigniswarteschlange).
Wenn während der Ausführung eine Mikroaufgabe auftritt, fügen Sie sie der Aufgabenwarteschlange der Mikroaufgabe hinzu
In der offiziellen Version handelt es sich um eine Standard-Mikrotask-Form
Polyfill, im Allgemeinen Es wird durch setTimeout simuliert, liegt also in Form einer Makrotask vor Beachten Sie, dass einige Browser unterschiedliche Ausführungsergebnisse haben (weil sie kann Mikrotask als Makrotask ausführen), aber der Einfachheit halber werden die Szenarien unter einigen nicht standardmäßigen Browsern hier nicht beschrieben (aber denken Sie daran, dass einige Browser möglicherweise nicht standardmäßig sind)
补充:使用MutationObserver实现microtask
MutationObserver可以用来实现microtask (它属于microtask,优先级小于Promise, 一般是Promise不支持时才会这样做)
它是HTML5中的新特性,作用是:监听一个DOM变动, 当DOM对象树发生任何变动时,Mutation Observer会得到通知
像以前的Vue源码中就是利用它来模拟nextTick的, 具体原理是,创建一个TextNode并监听内容变化, 然后要nextTick的时候去改一下这个节点的文本内容, 如下:
var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) }
不过,现在的Vue(2.5+)的nextTick实现移除了MutationObserver的方式(据说是兼容性原因), 取而代之的是使用MessageChannel (当然,默认情况仍然是Promise,不支持才兼容的)。
MessageChannel属于宏任务,优先级是:MessageChannel->setTimeout, 所以Vue(2.5+)内部的nextTick与2.4及之前的实现是不一样的,需要注意下。
【相关推荐:javascript视频教程、web前端】
Das obige ist der detaillierte Inhalt vonBeherrschen Sie den Funktionsmechanismus und die Prinzipien von JavaScript vollständig. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!