Ich bin kürzlich auf einen ziemlich bösen Fehler gestoßen, bei dem der Code <select>
dynamisch über JavaScript geladen wurde. Dieses dynamisch geladene <select>
hatte einen vorgewählten Wert. In IE6, wir Code bereits hatten die ausgewählt zu beheben <option>
, weil manchmal der <select>
‚s selectedIndex
würde Wert synchron aus dem ausgewählten <option>
‘ s index
Attribute, wie folgt:
field.selectedIndex = element.index;
Dieser Code funktionierte jedoch nicht. Obwohl die Felder selectedIndex
korrekt eingestellt wurden, wurde am Ende der falsche Index ausgewählt. Wenn ich jedoch eine alert()
Aussage zum richtigen Zeitpunkt einfügte, wurde die richtige Option ausgewählt. Da ich dachte, dies könnte ein Timing-Problem sein, versuchte ich etwas Zufälliges, das ich zuvor im Code gesehen hatte:
var wrapFn = (function() {
var myField = field;
var myElement = element;
return function() {
myField.selectedIndex = myElement.index;
}
})();
setTimeout(wrapFn, 0);
Und das hat funktioniert!
Ich habe eine Lösung für mein Problem, aber es ist mir unangenehm, dass ich nicht genau weiß, warum dies mein Problem behebt. Hat jemand eine offizielle Erklärung? Welches Browserproblem vermeide ich, indem ich meine Funktion "später" mit aufrufe setTimeout()
?
quelle
setTimeout(fn)
istsetTimeout(fn, 0)
übrigens dasselbe wie .Antworten:
In der Frage bestand eine Rassenbedingung zwischen:
Ihr Code hat dieses Rennen durchweg gewonnen und versucht, die Dropdown-Auswahl festzulegen, bevor der Browser bereit war, was bedeutet, dass der Fehler auftreten würde.
Diese Rasse bestand, weil JavaScript einen einzigen Ausführungsthread hat , der für das Rendern von Seiten freigegeben ist. Tatsächlich blockiert das Ausführen von JavaScript die Aktualisierung des DOM.
Ihre Problemumgehung war:
Wenn Sie
setTimeout
mit einem Rückruf und Null als zweitem Argument aufrufen, wird der Rückruf nach der kürzestmöglichen Verzögerung asynchron ausgeführt. Dies liegt bei etwa 10 ms, wenn die Registerkarte den Fokus hat und der JavaScript-Ausführungsthread nicht belegt ist.Die Lösung des OP bestand daher darin, die Einstellung des ausgewählten Index um etwa 10 ms zu verzögern. Dies gab dem Browser die Möglichkeit, das DOM zu initialisieren und den Fehler zu beheben.
Jede Version von Internet Explorer zeigte ein eigenartiges Verhalten, und diese Art der Problemumgehung war zeitweise erforderlich. Alternativ könnte es sich um einen echten Fehler in der Codebasis des OP handeln.
Sehen Sie, wie Philip Roberts spricht: "Was zum Teufel ist die Ereignisschleife?" für eine gründlichere Erklärung.
quelle
Vorwort:
Einige der anderen Antworten sind korrekt, veranschaulichen jedoch nicht das zu lösende Problem. Daher habe ich diese Antwort erstellt, um diese detaillierte Abbildung zu präsentieren.
Aus diesem Grund veröffentliche ich eine detaillierte Anleitung, was der Browser tut und wie die Verwendung
setTimeout()
hilft . Es sieht länger aus, ist aber eigentlich sehr einfach und unkompliziert - ich habe es nur sehr detailliert gemacht.UPDATE: Ich habe eine JSFiddle erstellt, um die folgende Erklärung live zu demonstrieren: http://jsfiddle.net/C2YBE/31/ . Vielen Dank an @ThangChung für die Unterstützung beim Kickstart.
UPDATE2: Nur für den Fall, dass die JSFiddle-Website stirbt oder den Code löscht, habe ich den Code ganz am Ende zu dieser Antwort hinzugefügt.
DETAILS :
Stellen Sie sich eine Web-App mit einer Schaltfläche "Etwas tun" und einem Ergebnis-Div vor.
Der
onClick
Handler für die Schaltfläche "etwas tun" ruft eine Funktion "LongCalc ()" auf, die zwei Dinge ausführt:Macht eine sehr lange Berechnung (dauert etwa 3 Minuten)
Druckt die Berechnungsergebnisse in das Ergebnis div.
Jetzt beginnen Ihre Benutzer, dies zu testen, klicken auf die Schaltfläche "etwas tun", und die Seite befindet sich dort und tut 3 Minuten lang scheinbar nichts. Sie werden unruhig. Klicken Sie erneut auf die Schaltfläche. Warten Sie 1 Minute. Es passiert nichts. Klicken Sie erneut auf die Schaltfläche.
Das Problem liegt auf der Hand - Sie möchten einen "Status" -DIV, der zeigt, was los ist. Mal sehen, wie das funktioniert.
Sie fügen also einen "Status" -DIV (anfangs leer) hinzu und ändern den
onclick
Handler (FunktionLongCalc()
), um 4 Dinge zu tun:Füllen Sie den Status "Berechnen ... kann ~ 3 Minuten dauern" in den Status DIV ein
Macht eine sehr lange Berechnung (dauert etwa 3 Minuten)
Druckt die Berechnungsergebnisse in das Ergebnis div.
Füllen Sie den Status "Berechnung erledigt" in den Status DIV
Und Sie geben die App gerne an Benutzer weiter, um sie erneut zu testen.
Sie kommen zu dir zurück und sehen sehr wütend aus. Und erklären Sie, dass der Status DIV beim Klicken auf die Schaltfläche nie mit dem Status "Berechnen ..." aktualisiert wurde !!!
Sie kratzen sich am Kopf, fragen bei StackOverflow nach (oder lesen Dokumente oder Google) und erkennen das Problem:
Der Browser platziert alle "TODO" -Aufgaben (sowohl UI-Aufgaben als auch JavaScript-Befehle), die sich aus Ereignissen ergeben, in einer einzigen Warteschlange . Und leider ist das erneute Zeichnen des DIV "Status" mit dem neuen Wert "Berechnen ..." ein separates TODO, das bis zum Ende der Warteschlange reicht!
Hier ist eine Aufschlüsselung der Ereignisse während des Tests Ihres Benutzers sowie der Inhalt der Warteschlange nach jedem Ereignis:
[Empty]
[Execute OnClick handler(lines 1-4)]
[Execute OnClick handler(lines 2-4), re-draw Status DIV with new "Calculating" value]
. Beachten Sie, dass Sie, während die DOM-Änderungen sofort erfolgen, zum erneuten Zeichnen des entsprechenden DOM-Elements ein neues Ereignis benötigen, das durch die DOM-Änderung am Ende der Warteschlange ausgelöst wird .[Execute OnClick handler(lines 3-4), re-draw Status DIV with "Calculating" value]
.[Execute OnClick handler(line 4), re-draw Status DIV with "Calculating" value, re-draw result DIV with result]
.[Execute OnClick handler, re-draw Status DIV with "Calculating" value, re-draw result DIV with result; re-draw Status DIV with "DONE" value]
.return
vomonclick
Handler-Sub. Wir nehmen den "Execute OnClick-Handler" aus der Warteschlange und beginnen mit der Ausführung des nächsten Elements in der Warteschlange.Das zugrunde liegende Problem besteht also darin, dass das Ereignis zum erneuten Zeichnen für "Status" DIV am Ende in die Warteschlange gestellt wird, NACH dem Ereignis "Zeile 2 ausführen", das 3 Minuten dauert, sodass das eigentliche erneute Zeichnen erst erfolgt Nachdem die Berechnung abgeschlossen ist.
Zur Rettung kommt der
setTimeout()
. Wie hilft es? Denn durch das Aufrufen von Code mit langer Ausführung übersetTimeout
erstellen Sie tatsächlich zwei Ereignisse: diesetTimeout
Ausführung selbst und (aufgrund eines Zeitlimits von 0) einen separaten Warteschlangeneintrag für den ausgeführten Code.Um Ihr Problem zu beheben, ändern Sie Ihren
onClick
Handler in ZWEI Anweisungen (in einer neuen Funktion oder nur in einem Block innerhalbonClick
):Füllen Sie den Status "Berechnen ... kann ~ 3 Minuten dauern" in den Status DIV ein
Führen
setTimeout()
mit 0 Timeout und einen AufrufLongCalc()
Funktion .LongCalc()
Funktion ist fast die gleiche wie beim letzten Mal, hat aber offensichtlich nicht den Status "Berechnen ..." DIV-Update als ersten Schritt; und startet stattdessen sofort die Berechnung.Wie sehen die Ereignissequenz und die Warteschlange jetzt aus?
[Empty]
[Execute OnClick handler(status update, setTimeout() call)]
[Execute OnClick handler(which is a setTimeout call), re-draw Status DIV with new "Calculating" value]
.[re-draw Status DIV with "Calculating" value]
. Die Warteschlange enthält noch 0 Sekunden lang nichts Neues.[re-draw Status DIV with "Calculating" value, execute LongCalc (lines 1-3)]
.[execute LongCalc (lines 1-3)]
. Bitte beachten Sie, dass dieses Ereignis zum erneuten Zeichnen tatsächlich eintreten kann, BEVOR der Alarm ausgelöst wird. Dies funktioniert genauso gut.Hurra! Der Status DIV wurde gerade vor Beginn der Berechnung auf "Berechnen ..." aktualisiert !!!
Unten finden Sie den Beispielcode von JSFiddle, der diese Beispiele veranschaulicht: http://jsfiddle.net/C2YBE/31/ :
HTML Quelltext:
JavaScript-Code: (Wird ausgeführt
onDomReady
und erfordert möglicherweise jQuery 1.9)quelle
Schauen Sie sich John Resigs Artikel über die Funktionsweise von JavaScript-Timern an . Wenn Sie eine Zeitüberschreitung festlegen, wird der asynchrone Code tatsächlich in die Warteschlange gestellt, bis die Engine den aktuellen Aufrufstapel ausführt.
quelle
setTimeout()
kauft Ihnen einige Zeit, bis die DOM-Elemente geladen sind, auch wenn sie auf 0 gesetzt sind.Überprüfen Sie dies: setTimeout
quelle
Die meisten Browser haben einen Prozess namens Hauptthread, der für die Ausführung einiger JavaScript-Aufgaben, UI-Updates verantwortlich ist, z. B. Malen, Neuzeichnen oder Reflow usw.
Einige Aufgaben zur Ausführung von JavaScript und zur Aktualisierung der Benutzeroberfläche werden in die Warteschlange für Browsermeldungen gestellt und dann an den auszuführenden Hauptthread des Browsers gesendet.
Wenn UI-Updates generiert werden, während der Hauptthread beschäftigt ist, werden die Aufgaben zur Nachrichtenwarteschlange hinzugefügt.
setTimeout(fn, 0);
Fügen Sie diesfn
am Ende der auszuführenden Warteschlange hinzu. Es plant, dass eine Aufgabe nach einer bestimmten Zeit in die Nachrichtenwarteschlange aufgenommen wird.quelle
add this fn to the end of the queue
. Am wichtigsten ist, wo genausetTimeout
diese Funktion, das Ende dieses Schleifenzyklus oder der Beginn des nächsten Schleifenzyklus hinzugefügt wird.Hier gibt es widersprüchliche Antworten, und ohne Beweise gibt es keine Möglichkeit zu wissen, wem man glauben soll. Hier ist der Beweis, dass @DVK richtig und @SalvadorDali falsch ist. Letzterer behauptet:
Die minimale Zeitüberschreitung von 4 ms ist für das, was passiert, irrelevant. Was wirklich passiert, ist, dass setTimeout die Rückruffunktion an das Ende der Ausführungswarteschlange schiebt. Wenn Sie nach setTimeout (Rückruf, 0) einen Sperrcode haben, dessen Ausführung einige Sekunden dauert, wird der Rückruf einige Sekunden lang nicht ausgeführt, bis der Sperrcode beendet ist. Versuchen Sie diesen Code:
Ausgabe ist:
quelle
Ein Grund dafür ist, die Ausführung von Code auf eine separate, nachfolgende Ereignisschleife zu verschieben. Wenn Sie auf ein Browserereignis reagieren (z. B. Mausklick), müssen Sie manchmal erst Operationen ausführen, nachdem das aktuelle Ereignis verarbeitet wurde. Die
setTimeout()
Einrichtung ist der einfachste Weg, dies zu tun.Bearbeiten Sie jetzt, da es 2015 ist. Ich sollte beachten, dass es auch gibt
requestAnimationFrame()
, was nicht genau das gleiche ist, aber es ist nahe genug,setTimeout(fn, 0)
dass es erwähnenswert ist.quelle
Dies ist eine alte Frage mit alten Antworten. Ich wollte dieses Problem neu betrachten und beantworten, warum dies geschieht und nicht, warum dies nützlich ist.
Sie haben also zwei Funktionen:
und rufen Sie sie dann in der folgenden Reihenfolge
f1(); f2();
auf, um zu sehen, dass die zweite zuerst ausgeführt wird.Und hier ist der Grund: Es ist nicht möglich,
setTimeout
mit einer Zeitverzögerung von 0 Millisekunden zu haben. Der Mindestwert wird vom Browser festgelegt und beträgt nicht 0 Millisekunden. In der Vergangenheit haben Browser dieses Minimum auf 10 Millisekunden festgelegt, in den HTML5-Spezifikationen und modernen Browsern jedoch auf 4 Millisekunden.Auch von Mozilla:
PS-Informationen werden nach dem Lesen des folgenden Artikels entnommen .
quelle
setTimeout(fn,0)
nützlich ist.setTimeout
/setInterval
mehr als fünf Ebenen tief verschachtelt haben . Wenn Sie dies nicht getan haben, beträgt das Minimum 0 ms (was bei fehlenden Zeitmaschinen der Fall ist). Mozillas Dokumente erweitern dies, um wiederholte, nicht nur verschachtelte Fälle abzudecken (setInterval
mit einem Intervall von 0 wird dies sofort einige Male neu geplant und danach länger verzögert), aber einfache VerwendungensetTimeout
mit minimaler Verschachtelung können sofort in die Warteschlange gestellt werden.Da es eine Dauer von übergeben wird
0
, wird es vermutlich verwendet, um den an den übergebenen CodesetTimeout
aus dem Ausführungsfluss zu entfernen . Wenn es sich also um eine Funktion handelt, die eine Weile dauern kann, wird die Ausführung des nachfolgenden Codes nicht verhindert.quelle
Diese beiden am besten bewerteten Antworten sind falsch. Schauen Sie sich die MDN-Beschreibung des Parallelitätsmodells und der Ereignisschleife an , und es sollte klar werden, was los ist (diese MDN-Ressource ist ein echtes Juwel). Und einfach zu verwenden
setTimeout
kann unerwartete Probleme in Ihren Code einfügen und dieses kleine Problem "lösen".Was hier tatsächlich vor sich geht, ist nicht, dass "der Browser möglicherweise noch nicht ganz bereit ist, weil Parallelität" oder etwas, das auf "jede Zeile ist ein Ereignis, das am Ende der Warteschlange hinzugefügt wird" basiert.
Die von DVK bereitgestellte jsfiddle zeigt zwar ein Problem, aber seine Erklärung dafür ist nicht korrekt.
Was in seinem Code passiert, ist, dass er zuerst einen Ereignishandler an das
click
Ereignis auf der#do
Schaltfläche anfügt.Wenn Sie dann tatsächlich auf die Schaltfläche klicken,
message
wird a erstellt, das auf die Ereignishandlerfunktion verweist, die der hinzugefügt wirdmessage queue
. Wenn derevent loop
diese Nachricht erreicht, wirdframe
auf dem Stapel ein Funktionsaufruf für den Click-Event-Handler in der jsfiddle erstellt.Und hier wird es interessant. Wir sind es so gewohnt, Javascript als asynchron zu betrachten, dass wir diese winzige Tatsache übersehen können: Jeder Frame muss vollständig ausgeführt werden, bevor der nächste Frame ausgeführt werden kann . Keine Parallelität, Leute.
Was bedeutet das? Dies bedeutet, dass bei jedem Aufruf einer Funktion aus der Nachrichtenwarteschlange die Warteschlange blockiert wird, bis der von ihr generierte Stapel geleert wurde. Oder allgemeiner gesagt, es wird blockiert, bis die Funktion zurückgekehrt ist. Und es blockiert alles , einschließlich DOM-Rendering-Operationen, Scrollen und so weiter. Wenn Sie eine Bestätigung wünschen, versuchen Sie einfach, die Dauer des lang laufenden Vorgangs in der Geige zu verlängern (z. B. die äußere Schleife noch 10 Mal ausführen), und Sie werden feststellen, dass Sie während der Ausführung nicht durch die Seite scrollen können. Wenn es lange genug läuft, werden Sie von Ihrem Browser gefragt, ob Sie den Vorgang abbrechen möchten, da die Seite dadurch nicht mehr reagiert. Der Frame wird ausgeführt, und die Ereignisschleife und die Nachrichtenwarteschlange bleiben hängen, bis sie beendet sind.
Warum wird dieser Nebeneffekt des Textes nicht aktualisiert? Denn während Sie haben den Wert des Elements in der DOM geändert - man kann
console.log()
seinen Wert unmittelbar nach dem Wechsel und sehen , dass es hat sich geändert (die zeigt , warum DVK Erklärung nicht korrekt ist) - der Browser für den Stapel zu verarmen wartet (dieon
Handlerfunktion, die zurückgegeben werden soll) und damit die Nachricht, die beendet werden soll, damit sie schließlich die Nachricht ausführen kann, die von der Laufzeit als Reaktion auf unsere Mutationsoperation hinzugefügt wurde, und um diese Mutation in der Benutzeroberfläche wiederzugeben .Dies liegt daran, dass wir tatsächlich darauf warten, dass der Code ausgeführt wird. Wir haben nicht gesagt, dass "jemand dies abruft und diese Funktion dann mit den Ergebnissen aufruft, danke, und jetzt bin ich fertig, also kehren Sie zurück, machen Sie jetzt was auch immer", wie wir es normalerweise mit unserem ereignisbasierten asynchronen Javascript tun. Wir geben eine Funktion Ereignishandler klicken, wir ein DOM - Element aktualisieren, rufen wir eine weitere Funktion, die andere Funktion arbeitet für eine lange Zeit und dann zurückkehrt, wir dann das gleiche DOM - Element aktualisieren, und dann kehren wir von der anfänglichen Funktion, effektiv Entleerung der Stapel. Und dann kann der Browser zur nächsten Nachricht in der Warteschlange gelangen, bei der es sich möglicherweise um eine Nachricht handelt, die von uns durch Auslösen eines internen Ereignisses vom Typ "On-DOM-Mutation" generiert wurde.
Die Benutzeroberfläche des Browsers kann die Benutzeroberfläche nicht aktualisieren (oder möchte dies nicht tun), bis der aktuell ausgeführte Frame abgeschlossen ist (die Funktion ist zurückgekehrt). Persönlich denke ich, dass dies eher beabsichtigt als einschränkend ist.
Warum funktioniert das
setTimeout
Ding dann? Dies geschieht, weil der Aufruf der Funktion mit langer Laufzeit effektiv aus dem eigenen Frame entfernt wird und die Ausführung später imwindow
Kontext geplant wird, sodass er selbst sofort zurückkehren und der Nachrichtenwarteschlange die Verarbeitung anderer Nachrichten ermöglichen kann. Die Idee ist, dass die Nachricht "On Update" der Benutzeroberfläche, die von uns in Javascript beim Ändern des Texts im DOM ausgelöst wurde, jetzt vor der Nachricht steht, die für die lang laufende Funktion in die Warteschlange gestellt wurde, sodass die Aktualisierung der Benutzeroberfläche vor dem Blockieren erfolgt Für eine lange Zeit.Beachten Sie, dass a) die Langzeitfunktion bei der Ausführung immer noch alles blockiert und b) Ihnen nicht garantiert werden kann, dass das UI-Update in der Nachrichtenwarteschlange tatsächlich vor Ihnen liegt. In meinem Chrome-Browser vom Juni 2018
0
"behebt" ein Wert von nicht das Problem, das die Geige demonstriert - 10. Ich bin tatsächlich ein bisschen erstickt, weil es mir logisch erscheint, dass die UI-Aktualisierungsnachricht davor in die Warteschlange gestellt werden sollte, da ihr Trigger ausgeführt wird, bevor die Langzeitfunktion "später" ausgeführt wird. Aber vielleicht gibt es einige Optimierungen in der V8-Engine, die stören könnten, oder vielleicht fehlt mir einfach mein Verständnis.Okay, was ist das Problem bei der Verwendung
setTimeout
und was ist eine bessere Lösung für diesen speziellen Fall?Zunächst einmal ist das Problem bei der Verwendung
setTimeout
eines solchen Ereignishandlers, um ein anderes Problem zu beheben, anfällig für Probleme mit anderem Code. Hier ist ein reales Beispiel aus meiner Arbeit:Ein Kollege versuchte in einem falsch informierten Verständnis der Ereignisschleife, Javascript zu "fädeln", indem er einen Code
setTimeout 0
zum Rendern von Vorlagen für das Rendern verwendete. Er ist nicht mehr hier, um zu fragen, aber ich kann davon ausgehen, dass er möglicherweise Timer eingefügt hat, um die Rendergeschwindigkeit zu messen (was die sofortige Rückgabe von Funktionen bedeuten würde), und festgestellt hat, dass die Verwendung dieses Ansatzes zu unglaublich schnellen Antworten dieser Funktion führen würde.Das erste Problem ist offensichtlich; Sie können kein Javascript einfädeln, daher gewinnen Sie hier nichts, während Sie die Verschleierung hinzufügen. Zweitens haben Sie jetzt das Rendern einer Vorlage effektiv vom Stapel möglicher Ereignis-Listener getrennt, die möglicherweise erwarten, dass genau diese Vorlage gerendert wurde, obwohl dies möglicherweise nicht der Fall war. Das tatsächliche Verhalten dieser Funktion war jetzt nicht deterministisch, ebenso wie - unwissentlich - jede Funktion, die sie ausführen würde oder von ihr abhängen würde. Sie können fundierte Vermutungen anstellen, aber Sie können das Verhalten nicht richtig codieren.
Das "Update" beim Schreiben eines neuen Ereignishandlers, der von seiner Logik abhing, sollte ebenfalls verwendet werden
setTimeout 0
. Aber das ist keine Lösung, es ist schwer zu verstehen und es macht keinen Spaß, Fehler zu debuggen, die durch solchen Code verursacht werden. Manchmal gibt es nie ein Problem, manchmal schlägt es immer wieder fehl, und manchmal funktioniert es und bricht sporadisch ab, abhängig von der aktuellen Leistung der Plattform und dem, was gerade passiert. Aus diesem Grund würde ich persönlich davon abraten, diesen Hack (es) zu verwenden ist ein Hack, und wir sollten alle wissen, dass dies der Fall ist), es sei denn, Sie wissen wirklich, was Sie tun und welche Konsequenzen dies hat.Aber was kann wir stattdessen tun? Wie aus dem MDN-Artikel hervorgeht, teilen Sie die Arbeit entweder in mehrere Nachrichten auf (wenn Sie können), damit andere Nachrichten, die sich in der Warteschlange befinden, mit Ihrer Arbeit verschachtelt und ausgeführt werden, während sie ausgeführt wird, oder verwenden Sie einen Web-Worker, der ausgeführt werden kann in Verbindung mit Ihrer Seite und geben Ergebnisse zurück, wenn die Berechnungen abgeschlossen sind.
Oh, und wenn Sie denken: "Nun, könnte ich nicht einfach einen Rückruf in die Langzeitfunktion einfügen, um sie asynchron zu machen?", Dann nein. Der Rückruf macht es nicht asynchron, es muss immer noch der lang laufende Code ausgeführt werden, bevor Ihr Rückruf explizit aufgerufen wird.
quelle
Das andere, was dies tut, ist, den Funktionsaufruf an den unteren Rand des Stapels zu verschieben, um einen Stapelüberlauf zu verhindern, wenn Sie eine Funktion rekursiv aufrufen. Dies hat den Effekt einer
while
Schleife, lässt jedoch die JavaScript-Engine andere asynchrone Timer auslösen.quelle
push the function invocation to the bottom of the stack
. Wasstack
du redest, ist dunkel. Am wichtigsten ist, wo genausetTimeout
diese Funktion, das Ende dieses Schleifenzyklus oder der Beginn des nächsten Schleifenzyklus hinzugefügt wird.Durch Aufrufen von setTimeout geben Sie der Seite Zeit, auf die Aktionen des Benutzers zu reagieren. Dies ist besonders hilfreich für Funktionen, die während des Ladens der Seite ausgeführt werden.
quelle
Einige andere Fälle, in denen setTimeout nützlich ist:
Sie möchten eine lange laufende Schleife oder Berechnung in kleinere Komponenten aufteilen, damit der Browser nicht "einfriert" oder "Skript auf Seite ist beschäftigt" sagt.
Sie möchten eine Schaltfläche zum Senden von Formularen deaktivieren, wenn Sie darauf klicken. Wenn Sie jedoch die Schaltfläche im onClick-Handler deaktivieren, wird das Formular nicht gesendet. setTimeout mit einer Zeit von Null macht den Trick, indem das Ereignis beendet wird, das Formular mit dem Senden beginnt und Ihre Schaltfläche deaktiviert werden kann.
quelle
Die Antworten zu Ausführungsschleifen und zum Rendern des DOM, bevor ein anderer Code abgeschlossen ist, sind korrekt. Null-Sekunden-Timeouts in JavaScript helfen dabei, den Code pseudo-multithreaded zu machen, obwohl dies nicht der Fall ist.
Ich möchte hinzufügen, dass der BESTE Wert für ein browser- / plattformübergreifendes Null-Sekunden-Timeout in JavaScript tatsächlich etwa 20 Millisekunden anstelle von 0 (Null) beträgt, da viele mobile Browser aufgrund von Taktbeschränkungen keine Timeouts von weniger als 20 Millisekunden registrieren können auf AMD-Chips.
Außerdem sollten lang laufende Prozesse, die keine DOM-Manipulation beinhalten, jetzt an Web Worker gesendet werden, da sie eine echte Multithread-Ausführung von JavaScript ermöglichen.
quelle
setTimout on 0 ist auch sehr nützlich beim Einrichten eines aufgeschobenen Versprechens, das Sie sofort zurückgeben möchten:
quelle
Das Problem war, dass Sie versucht haben, eine Javascript-Operation für ein nicht vorhandenes Element auszuführen. Das Element musste noch geladen werden und
setTimeout()
bietet mehr Zeit zum Laden eines Elements auf folgende Weise:setTimeout()
bewirkt, dass das Ereignis ansynchron ist und daher nach dem gesamten synchronen Code ausgeführt wird, sodass Ihr Element mehr Zeit zum Laden hat. Asynchrone Rückrufe wie der Rückruf insetTimeout()
werden in die Ereigniswarteschlange gestellt und von der Ereignisschleife auf den Stapel gelegt nachdem der Stapel des synchronen Codes leer ist.setTimeout()
ist häufig etwas höher (4-10 ms je nach Browser). Diese etwas höhere Zeit, die zum Ausführen dersetTimeout()
Rückrufe benötigt wird, wird durch die Anzahl der "Ticks" (die ein Tick einen Rückruf auf den Stapel drückt, wenn der Stapel leer ist) der Ereignisschleife verursacht. Aus Gründen der Leistung und der Akkulaufzeit ist die Anzahl der Ticks in der Ereignisschleife auf eine bestimmte Anzahl von weniger als 1000 Mal pro Sekunde beschränkt.quelle
Javascript ist eine Single-Threaded-Anwendung, die es nicht erlaubt, Funktionen gleichzeitig auszuführen, um dieses Ereignis zu erreichen. Es werden Schleifen verwendet. Was genau setTimeout (fn, 0) tut, ist, dass es sich um eine Aufgabenquest handelt, die ausgeführt wird, wenn Ihr Aufrufstapel leer ist. Ich weiß, dass diese Erklärung ziemlich langweilig ist, daher empfehle ich Ihnen, dieses Video durchzugehen. Dies wird Ihnen helfen, wie die Dinge unter der Haube im Browser funktionieren. Schauen Sie sich dieses Video an: - https://www.youtube.com/watch?time_continue=392&v=8aGhZQkoFbQ
quelle