Window: setTimeout() Methode
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Die setTimeout()
Methode der Window
-Schnittstelle setzt einen Timer, der eine Funktion oder ein angegebenes Codefragment ausführt, sobald der Timer abläuft.
Syntax
setTimeout(code)
setTimeout(code, delay)
setTimeout(functionRef)
setTimeout(functionRef, delay)
setTimeout(functionRef, delay, param1)
setTimeout(functionRef, delay, param1, param2)
setTimeout(functionRef, delay, param1, param2, /* …, */ paramN)
Parameter
functionRef
-
Eine
function
, die nach Ablauf des Timers ausgeführt werden soll. code
-
Eine alternative Syntax, die es Ihnen erlaubt, einen String anstelle einer Funktion einzuschließen, der kompiliert und ausgeführt wird, wenn der Timer abläuft. Diese Syntax wird nicht empfohlen wegen derselben Sicherheitsrisiken, die die Verwendung von
eval()
mit sich bringt. delay
Optional-
Die Zeit in Millisekunden, die der Timer warten soll, bevor die angegebene Funktion oder der Code ausgeführt wird. Wenn dieses Parameter weggelassen wird, wird ein Wert von 0 verwendet, was bedeutet, "sofort" ausführen, oder genauer, im nächsten Ereigniszyklus.
Beachten Sie, dass in beiden Fällen die tatsächliche Verzögerung länger als beabsichtigt sein kann; siehe Gründe für längere Verzögerungen als angegeben unten.
Beachten Sie auch, dass, wenn der Wert keine Zahl ist, eine implizite Typumwandlung stillschweigend auf den Wert angewendet wird, um ihn in eine Zahl zu konvertieren – was zu unerwarteten und überraschenden Ergebnissen führen kann; siehe Nicht-Zahlen-Verzögerungswerte werden stillschweigend in Zahlen umgewandelt für ein Beispiel.
param1
, …,paramN
Optional-
Zusätzliche Argumente, die an die Funktion übergeben werden, die von
functionRef
spezifiziert wird.
Rückgabewert
Der zurückgegebene timeoutID
ist ein positiver ganzzahliger Wert, der
den Timer identifiziert, der durch den Aufruf von setTimeout()
erstellt wurde. Dieser Wert kann
an clearTimeout()
übergeben werden, um den Timeout zu
stornieren.
Es ist garantiert, dass ein timeoutID
-Wert niemals durch einen nachfolgenden Aufruf von setTimeout()
oder setInterval()
im selben Fenster wiederverwendet wird, solange der Timer noch aktiv ist. Unterschiedliche Objekte verwenden jedoch separate ID-Pools.
Beschreibung
Timeouts werden mit Window.clearTimeout()
abgebrochen.
Um eine Funktion wiederholt aufzurufen (z.B. alle N Millisekunden), ziehen Sie die Verwendung von setInterval()
in Betracht.
Nicht-Zahlen-Verzögerungswerte werden stillschweigend in Zahlen umgewandelt
Wenn setTimeout()
mit einem delay-Wert aufgerufen wird, der keine Zahl ist, wird die implizite Typumwandlung stillschweigend auf den Wert angewendet, um ihn in eine Zahl zu konvertieren. Zum Beispiel verwendet der folgende Code fälschlicherweise den String "1000"
für den delay-Wert anstelle der Zahl 1000
– aber er funktioniert dennoch, weil beim Ausführen des Codes der String in die Zahl 1000
umgewandelt wird, und der Code daher 1 Sekunde später ausgeführt wird.
setTimeout(() => {
console.log("Delayed for 1 second.");
}, "1000");
Aber in vielen Fällen kann die implizite Typumwandlung zu unerwarteten und überraschenden Ergebnissen führen. Wenn z.B. der folgende Code ausgeführt wird, wird der String "1 second"
letztendlich in die Zahl 0
umgewandelt – und der Code wird sofort mit einer Verzögerung von null ausgeführt.
setTimeout(() => {
console.log("Delayed for 1 second.");
}, "1 second");
Daher sollten Sie keine Strings für den delay-Wert verwenden, sondern immer Zahlen:
setTimeout(() => {
console.log("Delayed for 1 second.");
}, 1000);
Arbeiten mit asynchronen Funktionen
setTimeout()
ist eine asynchrone Funktion, was bedeutet, dass die Timerfunktion die Ausführung anderer Funktionen im Funktionsstapel nicht pausieren wird.
Mit anderen Worten, Sie können setTimeout()
nicht verwenden, um eine "Pause" zu erstellen, bevor die nächste Funktion im Funktionsstapel ausgelöst wird.
Siehe das folgende Beispiel:
setTimeout(() => {
console.log("this is the first message");
}, 5000);
setTimeout(() => {
console.log("this is the second message");
}, 3000);
setTimeout(() => {
console.log("this is the third message");
}, 1000);
// Output:
// this is the third message
// this is the second message
// this is the first message
Beachten Sie, dass die erste Funktion keine 5-Sekunden-"Pause" erstellt, bevor die zweite Funktion aufgerufen wird. Stattdessen wird die erste Funktion aufgerufen, wartet jedoch 5 Sekunden auf die Ausführung. Während die erste Funktion auf die Ausführung wartet, wird die zweite Funktion aufgerufen, und es wird eine 3-Sekunden-Wartezeit auf die zweite Funktion angewendet, bevor sie ausgeführt wird. Da weder der Timer der ersten noch der der zweiten Funktion abgeschlossen ist, wird die dritte Funktion zuerst aufgerufen und abgeschlossen. Dann folgt die zweite. Schließlich wird die erste Funktion nach Abschluss ihres Timers ausgeführt.
Um eine Abfolge zu erstellen, bei der eine Funktion nur nach Abschluss einer anderen Funktion ausgelöst wird, lesen Sie die Dokumentation zu Promises.
Das "this"-Problem
Wenn Sie eine Methode an setTimeout()
übergeben, wird sie mit einem this
-Wert aufgerufen, der möglicherweise nicht Ihrer Erwartung entspricht. Das allgemeine Problem wird im JavaScript-Referenzdokument ausführlich erklärt.
Der von setTimeout()
ausgeführte Code wird aus einem Ausführungskontext aufgerufen, der von der Funktion getrennt ist, von der setTimeout
aufgerufen wurde. Die üblichen Regeln für das Festlegen des this
-Schlüsselworts für die aufgerufene Funktion gelten, und wenn Sie this
nicht im Aufruf oder mit bind
festgelegt haben, wird es standardmäßig auf das window
(oder global
) Objekt gesetzt, selbst im strict mode. Es ist nicht der gleiche this
-Wert für die Funktion, die setTimeout
aufgerufen hat.
Siehe das folgende Beispiel:
const myArray = ["zero", "one", "two"];
myArray.myMethod = function (sProperty) {
console.log(arguments.length > 0 ? this[sProperty] : this);
};
myArray.myMethod(); // prints "zero,one,two"
myArray.myMethod(1); // prints "one"
Das obige funktioniert, weil, wenn myMethod
aufgerufen wird, dessen this
durch den Aufruf auf myArray
gesetzt wird, so dass innerhalb der Funktion this[sProperty]
gleich myArray[sProperty]
ist. Jedoch im Folgenden:
setTimeout(myArray.myMethod, 1.0 * 1000); // prints "[object Window]" after 1 second
setTimeout(myArray.myMethod, 1.5 * 1000, "1"); // prints "undefined" after 1.5 seconds
Die Funktion myArray.myMethod
wird an setTimeout
übergeben, und wenn sie aufgerufen wird, ist this
nicht gesetzt, also wird es standardmäßig auf das window
-Objekt gesetzt.
Es gibt auch keine Option, ein thisArg
an setTimeout
zu übergeben, wie es in Array-Methoden wie forEach()
und reduce()
möglich ist. Wie unten gezeigt, funktioniert das Verwenden von call
, um this
zu setzen, auch nicht.
setTimeout.call(myArray, myArray.myMethod, 2.0 * 1000); // error
setTimeout.call(myArray, myArray.myMethod, 2.5 * 1000, 2); // same error
Lösungen
Verwenden Sie eine Wrapper-Funktion
Eine gängige Möglichkeit, das Problem zu lösen, ist die Verwendung einer Wrapper-Funktion, die this
auf den erforderlichen Wert setzt:
setTimeout(function () {
myArray.myMethod();
}, 2.0 * 1000); // prints "zero,one,two" after 2 seconds
setTimeout(function () {
myArray.myMethod("1");
}, 2.5 * 1000); // prints "one" after 2.5 seconds
Die Wrapper-Funktion kann eine Pfeilfunktion sein:
setTimeout(() => {
myArray.myMethod();
}, 2.0 * 1000); // prints "zero,one,two" after 2 seconds
setTimeout(() => {
myArray.myMethod("1");
}, 2.5 * 1000); // prints "one" after 2.5 seconds
Verwenden Sie bind()
Alternativ können Sie bind()
verwenden, um den Wert von this
für alle Aufrufe einer bestimmten Funktion festzulegen:
const myArray = ["zero", "one", "two"];
const myBoundMethod = function (sProperty) {
console.log(arguments.length > 0 ? this[sProperty] : this);
}.bind(myArray);
myBoundMethod(); // prints "zero,one,two" because 'this' is bound to myArray in the function
myBoundMethod(1); // prints "one"
setTimeout(myBoundMethod, 1.0 * 1000); // still prints "zero,one,two" after 1 second because of the binding
setTimeout(myBoundMethod, 1.5 * 1000, "1"); // prints "one" after 1.5 seconds
Übergeben von String-Literalen
Das Übergeben eines Strings anstelle einer Funktion an setTimeout()
hat dieselben Probleme wie die Verwendung von eval()
.
// Don't do this
setTimeout("console.log('Hello World!');", 500);
// Do this instead
setTimeout(() => {
console.log("Hello World!");
}, 500);
Ein an setTimeout()
übergebener String wird im globalen Kontext ausgewertet, so dass lokale Symbole im Kontext, in dem setTimeout()
aufgerufen wurde, nicht verfügbar sind, wenn der String als Code ausgewertet wird.
Gründe für längere Verzögerungen als angegeben
Es gibt eine Reihe von Gründen, warum ein Timeout länger als erwartet ausgelöst werden kann. Dieser Abschnitt beschreibt die häufigsten Gründe.
Verschachtelte Timeouts
Wie im HTML-Standard angegeben,
werden Browser ab einer verschachtelten Aufrufhöhe von 5 Aufrufen von setTimeout
eine Mindesttimeout von 4 Millisekunden erzwingen.
Das kann man im folgenden Beispiel sehen, in dem wir einen Aufruf von setTimeout
mit einer Verzögerung von 0
Millisekunden verschachteln,
und die Verzögerung bei jedem Aufruf der Handler-Funktion protokollieren. Die ersten vier Male beträgt die Verzögerung etwa 0 Millisekunden, danach etwa 4 Millisekunden:
<button id="run">Run</button>
<table>
<thead>
<tr>
<th>Previous</th>
<th>This</th>
<th>Actual delay</th>
</tr>
</thead>
<tbody id="log"></tbody>
</table>
let last = 0;
let iterations = 10;
function timeout() {
// log the time of this call
log(new Date().getMilliseconds());
// if we are not finished, schedule the next call
if (iterations-- > 0) {
setTimeout(timeout, 0);
}
}
function run() {
// clear the log
const log = document.querySelector("#log");
while (log.lastElementChild) {
log.removeChild(log.lastElementChild);
}
// initialize iteration count and the starting timestamp
iterations = 10;
last = new Date().getMilliseconds();
// start timer
setTimeout(timeout, 0);
}
function log(now) {
// log the last timestamp, the new timestamp, and the difference
const tableBody = document.getElementById("log");
const logRow = tableBody.insertRow();
logRow.insertCell().textContent = last;
logRow.insertCell().textContent = now;
logRow.insertCell().textContent = now - last;
last = now;
}
document.querySelector("#run").addEventListener("click", run);
Timeouts in inaktiven Tabs
Um die Last (und den damit verbundenen Batteriegebrauch) von Hintergrundtabs zu reduzieren, erzwingen Browser
eine Mindesttimeout-Verzögerung in inaktiven Tabs. Dies kann aufgehoben werden, wenn eine Seite Ton über eine Web Audio API AudioContext
abspielt.
Die Einzelheiten hierzu sind browserabhängig:
- Firefox Desktop und Chrome haben eine Mindesttimeout von 1 Sekunde für inaktive Tabs.
- Firefox für Android hat eine Mindesttimeout von 15 Minuten für inaktive Tabs und kann sie vollständig entladen.
- Firefox drosselt inaktive Tabs nicht, wenn der Tab einen
AudioContext
enthält.
Drosselung von Tracking-Skripten
Firefox erzwingt eine zusätzliche Drosselung für Skripte, die als Tracking-Skripte erkannt werden. Wenn sie im Vordergrund ausgeführt werden, beträgt die minimale Drosselungsverzögerung trotzdem 4 ms. In Hintergrundtabs beträgt die minimale Drosselungsverzögerung jedoch 10,000 ms oder 10 Sekunden, die 30 Sekunden nachdem ein Dokument erstmals geladen wurde, in Kraft tritt.
Weitere Details finden Sie unter Tracking Protection.
Späte Timeouts
Das Timeout kann auch später als erwartet ausgelöst werden, wenn die Seite (oder das Betriebssystem/der Browser) mit anderen Aufgaben beschäftigt ist.
Ein wichtiger Fall, den es zu beachten gilt, ist, dass die Funktion oder der Codeschnipsel nicht ausgeführt werden kann, bis der Thread, der setTimeout()
aufgerufen hat, beendet ist. Zum Beispiel:
function foo() {
console.log("foo has been called");
}
setTimeout(foo, 0);
console.log("After setTimeout");
Wird in die Konsole schreiben:
After setTimeout foo has been called
Dies liegt daran, dass, obwohl setTimeout
mit einer Verzögerung von null aufgerufen wurde, es in eine Warteschlange gestellt und beim nächsten geeigneten Zeitpunkt eingeplant wird; nicht sofort.
Aktuell ausgeführter Code muss abgeschlossen sein, bevor Funktionen in der Warteschlange ausgeführt werden, sodass die resultierende Ausführungsreihenfolge möglicherweise nicht wie erwartet ist.
Aufschub von Timeouts während des Seitenladens
Firefox wird setTimeout()
-Timer verzögern, während der aktuelle Tab geladen wird. Die Auslösung wird verschoben, bis der Hauptthread als
inaktiv betrachtet wird (ähnlich wie Window.requestIdleCallback()
),
oder bis das Ladeereignis ausgelöst wird.
WebExtension-Hintergrundseiten und Timer
In WebExtensions funktioniert setTimeout()
nicht zuverlässig. Erweiterungsautoren sollten stattdessen die alarms
API verwenden.
Maximale Verzögerungswert
Browser speichern die Verzögerung intern als 32-Bit-ganzzahliger Wert. Dies führt zu einem Ganzzahlüberlauf bei Verwendung von Verzögerungen, die größer als 2.147.483.647 ms (etwa 24,8 Tage) sind. So führt zum Beispiel dieser Code:
setTimeout(() => console.log("hi!"), 2 ** 32 - 5000);
…dazu, dass das Timeout sofort ausgeführt wird (da 2**32 - 5000
zu einer negativen Zahl überläuft), während der folgende Code:
setTimeout(() => console.log("hi!"), 2 ** 32 + 5000);
…dazu führt, dass das Timeout nach etwa 5 Sekunden ausgeführt wird.
Hinweis: Das entspricht nicht dem Verhalten von setTimeout
in Node.js, wo ein Timeout, das größer als 2.147.483.647 ms ist,
zu einer sofortigen Ausführung führt.
Beispiele
Setzen und Löschen von Timeouts
Das folgende Beispiel richtet zwei einfache Schaltflächen in einem Webdokument ein und verbindet sie mit den
setTimeout()
- und clearTimeout()
-Routinen. Durch Drücken der ersten
Schaltfläche wird ein Timeout eingestellt, das eine Nachricht nach zwei Sekunden anzeigt und die
Timeout-ID für die Verwendung durch clearTimeout()
speichert. Sie können optional diesen
Timeout abbrechen, indem Sie auf die zweite Schaltfläche drücken.
HTML
<button onclick="delayedMessage();">Show a message after two seconds</button>
<button onclick="clearMessage();">Cancel message before it happens</button>
<div id="output"></div>
JavaScript
let timeoutID;
function setOutput(outputContent) {
document.querySelector("#output").textContent = outputContent;
}
function delayedMessage() {
setOutput("");
timeoutID = setTimeout(setOutput, 2 * 1000, "That was really slow!");
}
function clearMessage() {
clearTimeout(timeoutID);
}
Ergebnis
Siehe auch das Beispiel zu clearTimeout()
.
Spezifikationen
Specification |
---|
HTML Standard # dom-settimeout-dev |
Browser-Kompatibilität
BCD tables only load in the browser