| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/de/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth | [Back] [Original] |
Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen bersetzt, und kann Fehler enthalten. Erfahre mehr ber dieses Experiment.
Beim Debuggen oder mglicherweise bei der Entscheidung ber den besten Ansatz zur Lsung eines Problems rund um das Timing und die Planung von Aufgaben und Microtasks kann es ntzlich sein, einige Details darber zu verstehen, wie die JavaScript-Laufzeit unter der Haube funktioniert.
JavaScript ist eine von Natur aus einzelfdige Sprache. Sie wurde in einer Zeit entwickelt, in der dies eine positive Entscheidung war; es gab nur wenige Mehrprozessor-Computer fr die breite ffentlichkeit und die erwartete Menge an Code, die von JavaScript verarbeitet werden wrde, war zu dieser Zeit relativ gering.
Im Laufe der Zeit haben sich Computer natrlich zu leistungsstarken Mehrkernsystemen entwickelt, und JavaScript ist eine der meistgenutzten Sprachen in der Computerwelt geworden. Eine Vielzahl der beliebtesten Anwendungen basiert zumindest teilweise auf JavaScript-Code. Um dies zu untersttzen, war es notwendig, Wege zu finden, um Projekte aus den Einschrnkungen einer einzelfdigen Sprache zu befreien.
Beginnend mit der Einfhrung von Timeouts und Intervallen als Teil der Web-API (setTimeout() und setInterval()) hat die von Webbrowsern bereitgestellte JavaScript-Umgebung allmhlich fortgeschrittene Funktionen entwickelt, die die Planung von Aufgaben, die Entwicklung mehrfdiger Anwendungen und so weiter ermglichen. Um zu verstehen, wo queueMicrotask() hier ins Spiel kommt, ist es hilfreich zu verstehen, wie die JavaScript-Laufzeit beim Planen und Ausfhren von Code operiert.
Hinweis: Die hier beschriebenen Details sind fr die meisten JavaScript-Programmierer im Allgemeinen nicht wichtig. Diese Informationen werden als Grundlage dafr bereitgestellt, warum Microtasks ntzlich sind und wie sie funktionieren; wenn es Sie nicht interessiert, knnen Sie diesen Abschnitt berspringen und spter zurckkommen, wenn Sie feststellen, dass Sie es brauchen.
Wenn ein Fragment von JavaScript-Code ausgefhrt wird, luft es in einem Ausfhrungskontext. Es gibt drei Arten von Code, die einen neuen Ausfhrungskontext erstellen:
eval() Funktion erstellt ebenfalls einen neuen Ausfhrungskontext.Jeder Kontext ist im Wesentlichen ein Geltungsbereich innerhalb Ihres Codes. Wenn eines dieser Code-Segmente mit der Ausfhrung beginnt, wird ein neuer Kontext erstellt, in dem es ausgefhrt wird; dieser Kontext wird dann beim Verlassen des Codes zerstrt. Betrachten Sie das folgende JavaScript-Programm:
const outputElem = document.getElementById("output");
const userLanguages = {
Mike: "en",
Teresa: "es",
};
function greetUser(user) {
function localGreeting(user) {
let greeting;
const language = userLanguages[user];
switch (language) {
case "es":
greeting = `Hola, ${user}!`;
break;
case "en":
default:
greeting = `Hello, ${user}!`;
break;
}
return greeting;
}
outputElem.innerText += `${localGreeting(user)}\n`;
}
greetUser("Mike");
greetUser("Teresa");
greetUser("Veronica");
Dieses kurze Programm enthlt drei Ausfhrungskontexte, von denen einige im Laufe der Programmausfhrung mehrmals erstellt und zerstrt werden. Jeder Kontext wird beim Erstellen auf den Ausfhrungskontext-Stack gelegt. Beim Beenden wird der Kontext von diesem Stack entfernt.
Beim Start des Programms wird der globale Kontext erstellt.
Wenn greetUser("Mike") erreicht wird, wird ein Kontext fr die greetUser()-Funktion erstellt; dieser Ausfhrungskontext wird auf den Ausfhrungskontext-Stack geschoben.
greetUser() die Funktion localGreeting() aufruft, wird ein weiterer Kontext erstellt, um diese Funktion auszufhren. Wenn diese Funktion zurckkehrt, wird der Kontext fr localGreeting() aus dem Ausfhrungsstack entfernt und zerstrt. Die Programmausfhrung wird mit dem nchsten Kontext im Stack fortgesetzt, was greetUser() ist; diese Funktion wird an der Stelle fortgesetzt, an der sie unterbrochen wurde.greetUser() kehrt zurck und ihr Kontext wird aus dem Stack entfernt und zerstrt.Wenn greetUser("Teresa") erreicht wird, wird ein Kontext dafr erstellt und auf den Stack geschoben.
greetUser() die Funktion localGreeting() aufruft, wird ein weiterer Kontext erstellt, um diese Funktion auszufhren. Wenn diese Funktion zurckkehrt, wird der Kontext fr localGreeting() aus dem Ausfhrungsstack entfernt und zerstrt. greetUser() wird an der Stelle fortgesetzt, an der es unterbrochen wurde.greetUser() kehrt zurck und ihr Kontext wird aus dem Stack entfernt und zerstrt.Wenn greetUser("Veronica") erreicht wird, wird ein Kontext dafr erstellt und auf den Stack geschoben.
greetUser() die Funktion localGreeting() aufruft, wird ein weiterer Kontext erstellt, um diese Funktion auszufhren. Wenn diese Funktion zurckkehrt, wird der Kontext fr localGreeting() aus dem Ausfhrungsstack entfernt und zerstrt.greetUser() kehrt zurck und ihr Kontext wird aus dem Stack entfernt und zerstrt.Das Hauptprogramm beendet sich, und sein Ausfhrungskontext wird aus dem Ausfhrungsstack entfernt; da keine Kontexte mehr im Stack vorhanden sind, endet die Programmausfhrung.
Durch die Verwendung von Ausfhrungskontexten auf diese Weise knnen jedes Programm und jede Funktion ihre eigene Menge an Variablen und anderen Objekten haben. Jeder Kontext verfolgt zudem die nchste Zeile im Programm, die ausgefhrt werden soll, und andere Informationen, die fr den Betrieb dieses Kontexts entscheidend sind. Durch die Verwendung der Kontexte und des Kontext-Stacks auf diese Weise knnen viele der Grundlagen der Programmablufe verwaltet werden, einschlielich lokaler und globaler Variablen, Funktionsaufrufen und -rckgaben und so weiter.
Eine besondere Anmerkung zu rekursiven Funktionendas sind Funktionen, die sich selbst aufrufen, mglicherweise ber mehrere Stufen der Rekursion: Jeder rekursive Aufruf der Funktion erstellt einen neuen Ausfhrungskontext. Dies ermglicht es der JavaScript-Laufzeit, die Ebenen der Rekursion und die Rckgabe von Ergebnissen durch diese Rekursion zu verfolgen, bedeutet aber auch, dass jedes Mal, wenn eine Funktion rekursiv aufgerufen wird, mehr Speicher bentigt wird, um den neuen Kontext zu erstellen.
Um JavaScript-Code auszufhren, hlt die Laufzeitumgebung ein Set von Agenten bereit, in dem JavaScript-Code ausgefhrt wird. Jeder Agent besteht aus einem Set von Ausfhrungskontexten, dem Ausfhrungskontext-Stack, einem Hauptthread, einem Set fr alle zustzlichen Threads, die mglicherweise erstellt werden, um Worker zu behandeln, einer Aufgabenwarteschlange und einer Microtask-Warteschlange. Abgesehen vom Hauptthreadden einige Browser ber mehrere Agenten hinweg teilenist jede Komponente eines Agenten einzigartig fr diesen Agenten.
Hier schauen wir uns an, wie die Laufzeitumgebung etwas detaillierter funktioniert.
Jeder Agent wird von einer Ereignisschleife angetrieben, die wiederholt durchlaufen wird. Whrend jeder Iteration luft hchstens eine ausstehende JavaScript-Aufgabe, dann alle ausstehenden Microtasks, dann wird jegliches notwendige Rendering und Malen durchgefhrt, bevor die Schleife erneut beginnt.
Der Code Ihrer Website oder Anwendung luft im selben Thread, der dieselbe Ereignisschleife verwendet wie die Benutzeroberflche des Webbrowsers selbst. Dies ist der Haupt-Thread, und zustzlich zur Ausfhrung des Hauptcodes Ihrer Website behandelt er das Empfangen und Verteilen von Benutzer- und anderen Ereignissen, das Rendern und Malen von Webinhalten und so weiter.
Die Ereignisschleife treibt also alles an, was im Browser in Bezug auf die Interaktion mit dem Benutzer passiert, ist aber wichtiger fr unsere Zwecke hier auch verantwortlich fr die Planung und Ausfhrung jedes Code-Snippets, das innerhalb ihres Threads luft.
Es gibt drei Arten von Ereignisschleifen:
Die Fenster-Ereignisschleife ist diejenige, die alle Fenster antreibt, die einen hnlichen Origin teilen (obwohl es hier, wie unten beschrieben, weitere Beschrnkungen gibt).
Eine Worker-Ereignisschleife ist eine, die einen Worker antreibt; dies umfasst alle Arten von Workern, einschlielich grundlegender Web-Worker, Shared Worker und Service Worker. Worker befinden sich in einem oder mehreren Agenten, die vom "Haupt"-Code getrennt sind; der Browser kann eine einzelne Ereignisschleife fr alle Worker eines bestimmten Typs verwenden oder mehrere Ereignisschleifen, um sie zu handhaben.
Eine Worklet-Ereignisschleife ist die Ereignisschleife, die Agenten antreibt, die den Code fr die Worklets eines bestimmten Agenten ausfhren. Dazu gehren Worklets des Typs Worklet und AudioWorklet.
Mehrere Fenster, die vom gleichen Origin geladen werden, knnen in derselben Ereignisschleife laufen und Aufgaben in die Ereignisschleife einreihen, damit ihre Aufgaben nacheinander bearbeitet werden. Beachten Sie, dass im Web-Jargon das Wort "Fenster" tatschlich "Browser-Level-Container, in dem Webinhalte ausgefhrt werden" bedeutet, einschlielich eines tatschlichen Fensters, eines Tabs oder eines Frames.
Es gibt spezifische Umstnde, in denen dieses Teilen einer Ereignisschleife unter Fenstern mit einem gemeinsamen Origin mglich ist, wie zum Beispiel:
<iframe> ist, teilt es wahrscheinlich eine Ereignisschleife mit dem Fenster, das es enthlt.Die Einzelheiten knnen je nach Browser variieren, je nachdem, wie sie implementiert sind.
Eine Aufgabe ist alles, was durch die Standardmechanismen wie das initiale Starten eines Scripts, das asynchrone Senden eines Ereignisses und so weiter geplant wird. Sie knnen eine Aufgabe auch durch die Verwendung von setTimeout() oder setInterval() in die Warteschlange einreihen.
Der Unterschied zwischen der Aufgabenwarteschlange und der Microtask-Warteschlange ist einfach, aber sehr wichtig:
Da Ihr Code im selben Thread luft und die gleiche Ereignisschleife verwendet wie die Benutzeroberflche des Browsers, wird der Browser selbst blockiert, wenn Ihr Code blockiert oder in eine Endlosschleife gert. Selbst eine langsame Leistung, sei es durch einen Fehler oder durch komplexe Arbeiten, die von Ihrem Code ausgefhrt werden, kann dazu fhren, dass der Benutzer einen trgen Browser erlebt.
Wenn mehrere Programme und mehrere Codeobjekte innerhalb dieser Programme gleichzeitig arbeiten mchten, neben einem Browser, der ebenfalls Prozessorzeit bentigt, geschweige denn Zeit, um die Website und ihre eigene Benutzeroberflche zu rendern und Ereignisse zu verarbeiten, wird heute alles viel zu leicht berlastet.
Die Verwendung von Web-Workern, die das Hauptskript erlauben, andere Skripte in neuen Threads auszufhren, hilft, dieses Problem zu lindern. Eine gut gestaltete Website oder App verwendet Worker, um komplexe oder langwierige Operationen durchzufhren, whrend der Haupt-Thread so wenig wie mglich arbeiten muss, abgesehen davon, die Webseite zu aktualisieren, zu layouten und zu rendern.
Dies wird weiter durch die Nutzung von asynchronem JavaScript reduziert, wie z.B. durch Promises, um es dem Hauptcode zu ermglichen, weiterzulaufen, whrend auf das Ergebnis einer Anfrage gewartet wird. Code, der jedoch auf einer grundlegenderen Ebene luftwie Code, der eine Bibliothek oder ein Framework bildetmglicherweise eine Mglichkeit bentigt, um Code zu einem sicheren Zeitpunkt im Haupt-Thread auszufhren, unabhngig von den Ergebnissen einer einzelnen Anfrage oder Aufgabe.
Microtasks sind eine weitere Lsung fr dieses Problem, da sie einen feineren Zugang bieten, indem sie es ermglichen, Code vor Beginn der nchsten Iteration der Ereignisschleife auszufhren, anstatt bis zur nchsten warten zu mssen.
Die Microtask-Warteschlange gibt es schon eine Weile, wurde aber historisch nur intern genutzt, um Dinge wie Promises anzutreiben. Die Hinzufgung von queueMicrotask(), das Entwicklern zur Verfgung gestellt wird, schafft eine einheitliche Warteschlange fr Microtasks, die berall verwendet wird, wo die Notwendigkeit besteht, Code sicher zu einem Zeitpunkt auszufhren, an dem keine Ausfhrungskontexte mehr auf dem JavaScript-Ausfhrungskontext-Stack vorhanden sind. Durch die Verwendung eines standardisierten Warteschlangensystems ber mehrere Instanzen und alle Browser und JavaScript-Laufzeiten hinweg arbeiten diese Microtasks zuverlssig in derselben Reihenfolge und vermeiden so potenziell schwer zu findende Fehler.
BeforeUnloadEventDOMStringMapErrorEventHashChangeEventImageDataHTMLAnchorElementHTMLAreaElementHTMLAudioElementHTMLBaseElementHTMLBodyElementHTMLBRElementHTMLButtonElementHTMLCanvasElementHTMLDataElementHTMLDataListElementHTMLDialogElementHTMLDivElementHTMLDListElementHTMLDocumentHTMLElementHTMLEmbedElementHTMLFieldSetElementHTMLFormControlsCollectionHTMLFormElementHTMLFrameSetElementHTMLGeolocationElementHTMLHeadElementHTMLHeadingElementHTMLHRElementHTMLHtmlElementHTMLIFrameElementHTMLImageElementHTMLInputElementHTMLLabelElementHTMLLegendElementHTMLLIElementHTMLLinkElementHTMLMapElementHTMLMediaElementHTMLMenuElementHTMLMetaElementHTMLMeterElementHTMLModElementHTMLObjectElementHTMLOListElementHTMLOptGroupElementHTMLOptionElementHTMLOptionsCollectionHTMLOutputElementHTMLParagraphElementHTMLPictureElementHTMLPreElementHTMLProgressElementHTMLQuoteElementHTMLScriptElementHTMLSelectElementHTMLSourceElementHTMLSpanElementHTMLStyleElementHTMLTableCaptionElementHTMLTableCellElementHTMLTableColElementHTMLTableElementHTMLTableRowElementHTMLTableSectionElementHTMLTextAreaElementHTMLTemplateElementHTMLTimeElementHTMLTitleElementHTMLTrackElementHTMLUListElementHTMLUnknownElementHTMLVideoElementHistoryLocationMessageChannelMessageEventMessagePortNavigatorPageRevealEventPageSwapEventPageTransitionEventPluginPluginArrayPromiseRejectionEventRadioNodeListTimeRangesUserActivationValidityStateWindowWorkletGlobalScopeDocument: DOMContentLoadedDocument: readystatechangeElement: afterscriptexecuteElement: auxclickElement: beforescriptexecuteElement: blurElement: clickElement: contextmenuElement: DOMActivateElement: focusElement: inputHTMLDialogElement: cancelHTMLDialogElement: closeHTMLElement: beforetoggleHTMLElement: changeHTMLElement: toggleHTMLFormElement: resetHTMLFormElement: submitHTMLInputElement: invalidHTMLInputElement: selectHTMLMediaElement: abortHTMLMediaElement: canplayHTMLMediaElement: canplaythroughHTMLMediaElement: durationchangeHTMLMediaElement: emptiedHTMLMediaElement: errorHTMLMediaElement: loadeddataHTMLMediaElement: loadedmetadataHTMLMediaElement: loadstartHTMLMediaElement: playHTMLMediaElement: playingHTMLMediaElement: progressHTMLMediaElement: seekedHTMLMediaElement: seekingHTMLMediaElement: stalledHTMLMediaElement: suspendHTMLMediaElement: timeupdateHTMLMediaElement: volumechangeHTMLMediaElement: waitingWindow: afterprintWindow: beforeprintWindow: beforeunloadWindow: hashchangeWindow: languagechangeWindow: loadWindow: messageWindow: offlineWindow: onlineWindow: pagehideWindow: pageshowWindow: rejectionhandledWindow: storageWindow: unloadWindow: unhandledrejectionDer Bauplan fr ein besseres Internet.
Teile dieses Inhalts sind 19982026 von einzelnen mozilla.org-Mitwirkenden. Inhalte sind verfgbar unter einer Creative-Commons-Lizenz.
| Web Proxy Viewer | New URL | Original Page |