| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/de/docs/Web/API/HTML_DOM_API/Microtask_guide | [Back] [Original] |
Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen bersetzt, und kann Fehler enthalten. Erfahre mehr ber dieses Experiment.
Eine Microtask ist eine kurze Funktion, die nach der Funktion oder dem Programm ausgefhrt wird, das sie erstellt hat und nur, wenn der JavaScript-Ausfhrungsstapel leer ist, jedoch bevor die Kontrolle wieder an die vom User Agent verwendete Ereignisschleife zurckgegeben wird, die die Ausfhrungsumgebung des Skripts antreibt.
Diese Ereignisschleife kann entweder die Hauptereignisschleife des Browsers oder die Ereignisschleife eines Web Workers sein. Dies ermglicht es der angegebenen Funktion, ohne das Risiko, die Ausfhrung eines anderen Skripts zu stren, zu laufen, und stellt gleichzeitig sicher, dass die Microtask ausgefhrt wird, bevor der User Agent die Mglichkeit hat, auf Aktionen zu reagieren, die von der Microtask durchgefhrt werden.
JavaScript-Promises und die Mutation Observer API verwenden beide die Microtask-Warteschlange, um ihre Rckrufe auszufhren, aber es gibt auch andere Flle, in denen die Mglichkeit, Arbeit bis zum Abschluss der aktuellen Ereignisschleifenpassage zu verschieben, hilfreich ist. Um die Verwendung von Microtasks durch Drittbibliotheken, Frameworks und Polyfills zu ermglichen, wird die Methode queueMicrotask() auf den Schnittstellen Window und WorkerGlobalScope bereitgestellt.
Um Microtasks richtig zu diskutieren, ist es zunchst ntzlich zu wissen, was eine JavaScript-Task ist und wie sich Microtasks von Tasks unterscheiden. Dies ist eine schnelle, vereinfachte Erklrung, aber wenn Sie mehr Details wnschen, knnen Sie die Informationen im Artikel Im Detail: Microtasks und die JavaScript-Laufzeitumgebung lesen.
Eine Task ist alles, was durch die Standardmechanismen ausgefhrt werden soll, wie z.B. das initiale Starten eines Programms, ein asynchron gesendetes Ereignis oder ein ausgelstes Intervall oder Timeout. All diese werden in die Task-Warteschlange eingereiht.
Beispielsweise werden Tasks zur Task-Warteschlange hinzugefgt, wenn:
<script>-Element) direkt.setTimeout() oder setInterval() erstelltes Timeout oder Intervall erreicht wird, was dazu fhrt, dass der entsprechende Rckruf in die Task-Warteschlange eingefgt wird.Die Ereignisschleife, die Ihren Code steuert, bearbeitet diese Tasks nacheinander in der Reihenfolge, in der sie eingereiht wurden. Die lteste ausfhrbare Task in der Task-Warteschlange wird whrend einer einzigen Iteration der Ereignisschleife ausgefhrt. Danach werden Microtasks ausgefhrt, bis die Microtask-Warteschlange leer ist, und dann kann der Browser das Rendering aktualisieren. Dann geht der Browser zur nchsten Iteration der Ereignisschleife ber.
Auf den ersten Blick scheint der Unterschied zwischen Microtasks und Tasks gering zu sein. Und sie sind hnlich; beide bestehen aus JavaScript-Code, der in eine Warteschlange gestellt wird und zur geeigneten Zeit ausgefhrt wird. Der Unterschied liegt jedoch darin, dass die Ereignisschleife nur die Tasks ausfhrt, die zu Beginn der Iteration in der Warteschlange waren, eine nach der anderen, whrend sie die Microtask-Warteschlange ganz anders handhabt.
Es gibt zwei wesentliche Unterschiede:
queueMicrotask() weitere Microtasks zur Warteschlange hinzufgt, werden diese neu hinzugefgten Microtasks ausgefhrt, bevor die nchste Task ausgefhrt wird. Das liegt daran, dass die Ereignisschleife Microtasks weiter aufruft, bis keine mehr in der Warteschlange sind, selbst wenn stndig weitere hinzugefgt werden.Warnung: Da Microtasks selbst mehr Microtasks einreihen knnen und die Ereignisschleife die Microtasks weiter bearbeitet, bis die Warteschlange leer ist, besteht ein echtes Risiko, dass die Ereignisschleife endlos Microtasks verarbeitet. Gehen Sie vorsichtig vor, wenn Sie rekursiv Microtasks hinzufgen.
Bevor wir weiter ins Detail gehen, ist es wichtig, nochmals zu betonen, dass die meisten Entwickler Microtasks kaum oder gar nicht verwenden werden. Sie sind ein hochspezialisiertes Feature der modernen browserbasierten JavaScript-Entwicklung, das es Ihnen ermglicht, Code vor anderen Dingen in der langen Liste der Dinge, die auf dem Computer des Benutzers passieren, zu planen. Missbrauch dieser Fhigkeit wird zu Leistungsproblemen fhren.
Daher sollten Sie Microtasks typischerweise nur verwenden, wenn es keine andere Lsung gibt oder wenn Sie Frameworks oder Bibliotheken erstellen, die zur Implementierung der von ihnen bereitgestellten Funktionalitt Microtasks nutzen mssen. Whrend es in der Vergangenheit Tricks gab, die es ermglichten, Microtasks einzureihen (wie das sofortige Auflsen eines Promises), fgt die Methode queueMicrotask() eine standardisierte Mglichkeit hinzu, eine Microtask sicher und ohne Tricks einzufhren.
Durch die Einfhrung von queueMicrotask() knnen die Eigenheiten vermieden werden, die auftreten, wenn man sich mit Promises zur Erstellung von Microtasks einmischt. Zum Beispiel werden bei der Verwendung von Promises zur Erstellung von Microtasks Ausnahmen, die vom Rckruf ausgelst werden, als abgelehnte Promises anstatt als Standardausnahmen gemeldet. Auerdem verursachen das Erstellen und Zerstren von Promises zustzlichen Aufwand, sowohl in Bezug auf Zeit als auch auf Speicher, den eine Funktion, die Microtasks ordnungsgem einreiht, vermeidet.
bergeben Sie die JavaScript-Function, die aufgerufen werden soll, whrend der Kontext Microtasks verarbeitet, an die queueMicrotask()-Methode, die im globalen Kontext bereitgestellt wird, wie es entweder von der Window- oder der Worker-Schnittstelle definiert ist, abhngig vom aktuellen Ausfhrungskontext.
queueMicrotask(() => {
/* code to run in the microtask here */
});
Die Microtask-Funktion selbst nimmt keine Parameter entgegen und gibt keinen Wert zurck.
In diesem Abschnitt betrachten wir Szenarien, in denen Microtasks besonders ntzlich sind. Im Allgemeinen geht es darum, Ergebnisse zu erfassen oder zu prfen oder Bereinigungen durchzufhren, nachdem der Hauptkrper eines JavaScript-Ausfhrungskontextes beendet istaber bevor Ereignis-Handler, Timeouts und Intervalle oder andere Rckrufe verarbeitet werden.
Wann ist das ntzlich?
Der Hauptgrund fr die Verwendung von Microtasks ist es, die konsistente Reihenfolge von Tasks sicherzustellen, selbst wenn Ergebnisse oder Daten synchron verfgbar sind, und gleichzeitig das Risiko von fr den Benutzer wahrnehmbaren Verzgerungen bei Operationen zu reduzieren.
Eine Situation, in der Microtasks verwendet werden knnen, um sicherzustellen, dass die Reihenfolge der Ausfhrung immer konsistent ist, ist, wenn Promises in einer Klausel einer if...else-Anweisung (oder einer anderen bedingten Anweisung) verwendet werden, aber nicht in der anderen Klausel. Betrachten Sie Code wie diesen:
customElement.prototype.getData = function (url) {
if (this.cache[url]) {
this.data = this.cache[url];
this.dispatchEvent(new Event("load"));
} else {
fetch(url)
.then((result) => result.arrayBuffer())
.then((data) => {
this.cache[url] = data;
this.data = data;
this.dispatchEvent(new Event("load"));
});
}
};
Das hier eingefhrte Problem besteht darin, dass wir durch die Verwendung einer Task in einem Zweig der if...else-Anweisung (im Fall, in dem das Bild im Cache verfgbar ist), aber indem Promises in der else-Klausel involviert sind, eine Situation haben, in der die Reihenfolge der Operationen variieren kann; zum Beispiel, wie unten gezeigt.
element.addEventListener("load", () => console.log("Loaded data"));
console.log("Fetching data");
element.getData();
console.log("Data fetched");
Das zweimalige Ausfhren dieses Codes ergibt die folgenden Ergebnisse.
Wenn die Daten nicht im Cache sind:
Fetching data Data fetched Loaded data
Wenn die Daten im Cache sind:
Fetching data Loaded data Data fetched
Noch schlimmer ist, dass manchmal die data-Eigenschaft des Elements gesetzt wird, aber andere Male wird sie nicht abgeschlossen, bevor dieser Code abgeschlossen ist.
Wir knnen eine konsistente Reihenfolge dieser Operationen sicherstellen, indem wir eine Microtask in der if-Klausel verwenden, um die beiden Klauseln auszugleichen:
customElement.prototype.getData = function (url) {
if (this.cache[url]) {
queueMicrotask(() => {
this.data = this.cache[url];
this.dispatchEvent(new Event("load"));
});
} else {
fetch(url)
.then((result) => result.arrayBuffer())
.then((data) => {
this.cache[url] = data;
this.data = data;
this.dispatchEvent(new Event("load"));
});
}
};
Dies gleicht die Klauseln aus, indem beide Situationen das Setzen von data und das Auslsen des load-Ereignisses innerhalb einer Microtask behandeln (Verwendung von queueMicrotask() in der if-Klausel und Verwendung der Promises durch fetch() in der else-Klausel).
Sie knnen auch Microtasks verwenden, um mehrere Anfragen aus verschiedenen Quellen zu einer einzigen Charge zu sammeln, um den mglichen Aufwand, der mit mehreren Anrufen zur Behandlung derselben Art von Arbeit verbunden ist, zu vermeiden.
Der untenstehende Codeausschnitt erstellt eine Funktion, die mehrere Nachrichten in einem Array stapelt, indem eine Microtask verwendet wird, um sie als ein einziges Objekt zu senden, wenn der Kontext beendet wird.
const messageQueue = [];
let sendMessage = (message) => {
messageQueue.push(message);
if (messageQueue.length === 1) {
queueMicrotask(() => {
const json = JSON.stringify(messageQueue);
messageQueue.length = 0;
fetch("url-of-receiver", json);
});
}
};
Wenn sendMessage() aufgerufen wird, wird die angegebene Nachricht zunchst dem Nachrichtenwarteschlangen-Array hinzugefgt. Dann wird es interessant.
Wenn die gerade hinzugefgte Nachricht die erste ist, reihen wir eine Microtask ein, die eine Charge sendet. Die Microtask wird ausgefhrt, wie immer, wenn der JavaScript-Ausfhrungspfad die oberste Ebene erreicht, kurz bevor Rckrufe ausgefhrt werden. Das bedeutet, dass alle weiteren Aufrufe von sendMessage(), die in der Zwischenzeit erfolgen, ihre Nachrichten in die Nachrichtenwarteschlange schieben werden, aber aufgrund der Array-Lngenberprfung, bevor eine Microtask hinzugefgt wird, wird keine neue Microtask eingereiht.
Wenn die Microtask ausgefhrt wird, hat sie also ein Array von mglicherweise vielen wartenden Nachrichten. Es beginnt damit, es als JSON mit der JSON.stringify()-Methode zu kodieren. Danach sind die Inhalte des Arrays nicht mehr erforderlich, also leeren wir das messageQueue-Array. Schlielich verwenden wir die fetch()-Methode, um den JSON-String an den Server zu senden.
Dies ermglicht es jedem Aufruf von sendMessage(), der whrend derselben Iteration der Ereignisschleife gemacht wird, ihre Nachrichten an dieselbe fetch()-Operation hinzuzufgen, ohne dass mglicherweise andere Tasks wie Timeouts oder hnliches die bertragung verzgern.
Der Server wird den JSON-String empfangen, dann voraussichtlich dekodieren und die Nachrichten verarbeiten, die er im resultierenden Array findet.
In diesem einfachen Beispiel sehen wir, dass das Einreihen einer Microtask dazu fhrt, dass der Rckruf der Microtask ausgefhrt wird, nachdem der Hauptkrper dieses obersten Skripts fertig ist.
<pre id="log"></pre>
const logElem = document.getElementById("log");
const log = (s) => (logElem.innerText += `${s}\n`);
Im folgenden Code sehen wir einen Aufruf von queueMicrotask(), um eine Microtask auszufhren. Dieser Aufruf wird von Anrufen an log(), einer benutzerdefinierten Funktion, die Text auf dem Bildschirm ausgibt, umrahmt.
log("Before enqueueing the microtask");
queueMicrotask(() => {
log("The microtask has run.");
});
log("After enqueueing the microtask");
In diesem Beispiel wird ein Timeout geplant, das nach null Millisekunden (oder so bald wie mglich) ausgelst wird. Dies demonstriert den Unterschied zwischen dem, was so bald wie mglich bedeutet, wenn eine neue Task geplant wird (wie mit setTimeout()) im Vergleich zur Verwendung einer Microtask.
<pre id="log"></pre>
const logElem = document.getElementById("log");
const log = (s) => (logElem.innerText += `${s}\n`);
Im folgenden Code sehen wir einen Aufruf von queueMicrotask(), um eine Microtask auszufhren. Dieser Aufruf wird von Anrufen an log(), einer benutzerdefinierten Funktion, die Text auf dem Bildschirm ausgibt, umrahmt.
Der Code unten plant ein Timeout, das in null Millisekunden auftritt, und reiht dann eine Microtask ein. Dies wird von Aufrufen an log() umrahmt, um zustzliche Nachrichten auszugeben.
const callback = () => log("Regular timeout callback has run");
const urgentCallback = () => log("*** Oh noes! An urgent callback has run!");
log("Main program started");
setTimeout(callback, 0);
queueMicrotask(urgentCallback);
log("Main program exiting");
Beachten Sie, dass die von dem Hauptprogrammkrper protokollierte Ausgabe zuerst erscheint, gefolgt von der Ausgabe der Microtask, gefolgt vom Rckruf des Timeouts. Das liegt daran, dass, wenn die Task, die die Ausfhrung des Hauptprogramms bearbeitet, endet, die Microtask-Warteschlange verarbeitet wird, bevor die Task-Warteschlange, auf der sich der Timeout-Rckruf befindet, bearbeitet wird. Um dies im Kopf zu behalten, denken Sie daran, dass Tasks und Microtasks in separaten Warteschlangen gehalten werden und dass Microtasks zuerst ausgefhrt werden.
Dieses Beispiel erweitert das vorherige leicht, indem eine Funktion hinzugefgt wird, die eine Arbeit ausfhrt. Diese Funktion verwendet queueMicrotask(), um eine Microtask zu planen. Das Wichtigste, das Sie hier mitnehmen sollten, ist, dass die Microtask nicht verarbeitet wird, wenn die Funktion endet, sondern wenn das Hauptprogramm endet.
<pre id="log"></pre>
const logElem = document.getElementById("log");
const log = (s) => (logElem.innerText += `${s}\n`);
Der folgende Hauptprogrammcode folgt. Die doWork()-Funktion hier ruft queueMicrotask() auf, und dennoch wird die Microtasks nicht ausgefhrt, bis das gesamte Programm endet, da das die Task beendet und nichts anderes mehr im Ausfhrungsstapel ist.
const callback = () => log("Regular timeout callback has run");
const urgentCallback = () => log("*** Oh noes! An urgent callback has run!");
const doWork = () => {
let result = 1;
queueMicrotask(urgentCallback);
for (let i = 2; i <= 10; i++) {
result *= i;
}
return result;
};
log("Main program started");
setTimeout(callback, 0);
log(`10! equals ${doWork()}`);
log("Main program exiting");
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 |