forked from mdn/content
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
365 lines (272 loc) · 14.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
---
title: setTimeout()
slug: Web/API/setTimeout
tags:
- API
- HTML DOM
- Intervals
- JavaScript timers
- MakeBrowserAgnostic
- Method
- NeedsMarkupWork
- Reference
- Timers
- setTimeout
- Polyfill
browser-compat: api.setTimeout
---
<div>{{APIRef("HTML DOM")}}</div>
<p>The global <strong><code>setTimeout()</code></strong> method sets a timer which executes a function or specified
piece of code once the timer expires.</p>
<h2 id="Syntax">Syntax</h2>
<pre class="brush: js">var <var>timeoutID</var> = setTimeout(<var>function</var>[, <var>delay</var>, <var>arg1</var>, <var>arg2</var>, ...]);
var <var>timeoutID</var> = setTimeout(<var>function</var>[, <var>delay</var>]);
var <var>timeoutID</var> = setTimeout(<var>code</var>[, <var>delay</var>]);
</pre>
<h3 id="Parameters">Parameters</h3>
<dl>
<dt><code><var>function</var></code></dt>
<dd>A {{jsxref("function")}} to be executed after the timer expires.</dd>
<dt><code><var>code</var></code></dt>
<dd>An alternative syntax that allows you to include a string instead of a function,
which is compiled and executed when the timer expires. This syntax is <strong>not
recommended</strong> for the same reasons that make using
{{jsxref("Global_Objects/eval", "eval()")}} a security risk.</dd>
<dt><code><var>delay</var></code> {{optional_inline}}</dt>
<dd>The time, in milliseconds that the timer should wait before
the specified function or code is executed. If this parameter is omitted, a value of 0
is used, meaning execute "immediately", or more accurately, the next event cycle. Note
that in either case, the actual delay may be longer than intended; see
{{anch("Reasons_for_delays", "Reasons for delays longer than specified")}} below.</dd>
<dt><code><var>arg1</var>, ..., <var>argN</var></code> {{optional_inline}}</dt>
<dd>Additional arguments which are passed through to the function specified by
<code><var>function</var></code>.</dd>
</dl>
<h3 id="Return_value">Return value</h3>
<p>The returned <code><var>timeoutID</var></code> is a positive integer value which
identifies the timer created by the call to <code>setTimeout()</code>. This value can be
passed to {{domxref("clearTimeout","clearTimeout()")}} to
cancel the timeout.</p>
<p>It is guaranteed that a <code><var>timeoutID</var></code> value will never be reused by a subsequent call to
<code>setTimeout()</code> or <code>setInterval()</code> on the same object (a window or
a worker). However, different objects use separate pools of IDs.</p>
<h2>Description</h2>
<p>Timeouts are cancelled using
{{domxref("clearTimeout()")}}.</p>
<p>To call a function repeatedly (e.g., every <em>N</em> milliseconds), consider using
{{domxref("setInterval()")}}.</p>
<h3 id="The_this_problem">The "this" problem</h3>
<p>When you pass a method to <code>setTimeout()</code>, it will be invoked with a <code>this</code> value that may differ from your
expectation. The general issue is explained in detail in the <a
href="/en-US/docs/Web/JavaScript/Reference/Operators/this#as_an_object_method">JavaScript
reference</a>.</p>
<p>Code executed by <code>setTimeout()</code> is called from an execution context separate
from the function from which <code>setTimeout</code> was called. The usual rules for
setting the <code>this</code> keyword for the called function apply, and if you have not
set <code>this</code> in the call or with <code>bind</code>, it will default to
the <code>window</code> (or <code>global</code>) object. It will not be the same as the
<code>this</code> value for the function that called <code>setTimeout</code>.</p>
<p>See the following example:</p>
<pre class="brush: js">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"</pre>
<p>The above works because when <code>myMethod</code> is called, its <code>this</code> is
set to <code>myArray</code> by the call, so within the function,
<code>this[sProperty]</code> is equivalent to <code>myArray[sProperty]</code>. However,
in the following:</p>
<pre
class="brush: js">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</pre>
<p>The <code>myArray.myMethod</code> function is passed to <code>setTimeout</code>, then
when it's called, its <code>this</code> is not set so it defaults to the
<code>window</code> object.</p>
<p>There's also no option to pass a <code>thisArg</code> to
<code>setTimeout</code> as there is in Array methods such as {{jsxref("Array.forEach()", "forEach()")}} and {{jsxref("Array.reduce()", "reduce()")}}. As shown below,
using <code>call</code> to set <code>this</code> doesn't work either.</p>
<pre class="brush: js">setTimeout.call(myArray, myArray.myMethod, 2.0*1000); // error
setTimeout.call(myArray, myArray.myMethod, 2.5*1000, 2); // same error
</pre>
<h4 id="solutions">Solutions</h4>
<h5>Use a wrapper function</h5>
<p>A common way to solve the problem is to use a wrapper function that sets
<code>this</code> to the required value:</p>
<pre
class="brush: js">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</pre>
<p>The wrapper function can be an arrow function:</p>
<pre
class="brush: js">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</pre>
<h5>Use bind()</h5>
<p>Alternatively, you can use {{jsxref("Function.bind()", "bind()")}} to set the value of <code>this</code> for all calls to a given function:</p>
<pre class="brush: js">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
</pre>
<h3 id="Passing_string_literals">Passing string literals</h3>
<p>Passing a string instead of a function to <code>setTimeout()</code> has the same problems as using
<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval">eval()</a></code>.
</p>
<pre class="brush: js example-bad">// Don't do this
setTimeout("console.log('Hello World!');", 500);
</pre>
<pre class="brush: js example-good">// Do this instead
setTimeout(function() {
console.log('Hello World!');
}, 500);
</pre>
<p>A string passed to <code>{{domxref("WindowOrworkerGlobalScope.setTimeout","setTimeout()")}}</code> is evaluated in the global context, so local symbols in the context where <code>{{domxref("WindowOrworkerGlobalScope.setTimeout","setTimeout()")}}</code> was called will not be available when the string is evaluated as code.</p>
<h3 id="Reasons_for_delays">Reasons for delays longer than specified</h3>
<p>There are a number of reasons why a timeout may take longer to fire than anticipated.
This section describes the most common reasons.</p>
<h4 id="Nested_timeouts">Nested timeouts</h4>
<p>As specified in the <a href="https://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers">HTML standard</a>,
browsers will enforce a minimum timeout of 4 milliseconds once a nested call to <code>setTimeout</code> has been scheduled 5 times.</p>
<p>This can be seen in the following example, in which we nest a call to <code>setTimeout</code> with a delay of <code>0</code> milliseconds,
and log the delay each time the handler is called. The first four times, the delay is approximately 0 milliseconds, and after that it is
approximately 4 milliseconds:</p>
<pre class="brush: html"><button id="run">Run</button>
<pre>previous this actual delay</pre>
<div id="log"></div>
</pre>
<pre class="brush: js">
let last = 0;
let iterations = 10;
function timeout() {
// log the time of this call
logline(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 pad(number) {
return number.toString().padStart(3, "0");
}
function logline(now) {
// log the last timestamp, the new timestamp, and the difference
const newLine = document.createElement("pre");
newLine.textContent = `${pad(last)} ${pad(now)} ${now - last}`;
document.getElementById("log").appendChild(newLine);
last = now;
}
document.querySelector("#run").addEventListener("click", run);
</pre>
<p>{{EmbedLiveSample("Nested_timeouts", 100, 420)}}</p>
<h4 id="Timeouts_in_inactive_tabs">Timeouts in inactive tabs</h4>
<p>To reduce the load (and associated battery usage) from background tabs, browsers will enforce
a minimum timeout delay in inactive tabs. It may also be waived if a page is playing sound
using a Web Audio API {{domxref("AudioContext")}}.</p>
<p>The specifics of this are browser-dependent:</p>
<ul>
<li>Firefox Desktop and Chrome both have a minimum timout of 1 second for inactive tabs.</li>
<li>Firefox for Android has a minimum timout of 15 minutes for inactive tabs and may unload them entirely.</li>
<li>Firefox does not throttle inactive tabs if the tab contains an {{domxref("AudioContext")}}.</li>
</ul>
<h4 id="Throttling_of_tracking_scripts">Throttling of tracking scripts</h4>
<p>Firefox enforces additional throttling for scripts that it recognises as tracking scripts.
When running in the foreground, the throttling minimum delay is still 4ms. In background tabs, however,
the throttling minimum delay is 10,000 ms, or 10 seconds, which comes into effect 30 seconds after a
document has first loaded.</p>
<p>See <a href="https://wiki.mozilla.org/Security/Tracking_protection">Tracking Protection</a> for
more details.</p>
<h4 id="Late_timeouts">Late timeouts</h4>
<p>The timeout can also fire later than expected if the page (or the OS/browser) is busy with other tasks.
One important case to note is that the function or code snippet cannot be executed until
the thread that called <code>setTimeout()</code> has terminated. For example:</p>
<pre class="brush: js">function foo() {
console.log('foo has been called');
}
setTimeout(foo, 0);
console.log('After setTimeout');</pre>
<p>Will write to the console:</p>
<pre>After setTimeout
foo has been called</pre>
<p>This is because even though <code>setTimeout</code> was called with a delay of zero,
it's placed on a queue and scheduled to run at the next opportunity; not immediately.
Currently-executing code must complete before functions on the queue are executed, thus
the resulting execution order may not be as expected.</p>
<h4 id="Deferral_of_timeouts_during_pageload">Deferral of timeouts during pageload</h4>
<p>Firefox will defer firing <code>setTimeout()</code> timers
while the current tab is loading. Firing is deferred until the main thread is deemed
idle (similar to <a
href="/en-US/docs/Web/API/Window/requestIdleCallback">window.requestIdleCallback()</a>),
or until the load event is fired.</p>
<h3 id="WebExtension_background_pages_and_timers">WebExtension background pages and timers
</h3>
<p>In <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions">WebExtensions</a>, <code>setTimeout()</code>
does not work reliably. Extension authors should use the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/alarms"><code>alarms</code></a>
API instead.</p>
<h3 id="Maximum_delay_value">Maximum delay value</h3>
<p>Browsers including Internet Explorer, Chrome, Safari, and Firefox store the delay as a
32-bit signed integer internally. This causes an integer overflow when using delays
larger than 2,147,483,647 ms (about 24.8 days), resulting in the timeout being executed
immediately.</p>
<h2 id="Example">Examples</h2>
<h3 id="Setting_and_clearing_timeouts">Setting and clearing timeouts</h3>
<p>The following example sets up two simple buttons in a web page and hooks them to the
<code>setTimeout()</code> and <code>clearTimeout()</code> routines. Pressing the first
button will set a timeout which shows a message after two seconds and stores the
timeout id for use by <code>clearTimeout()</code>. You may optionally cancel this
timeout by pressing on the second button.</p>
<h4 id="HTML">HTML</h4>
<pre class="brush: html">
<button onclick="delayedMessage();">Show an message after two seconds</button>
<button onclick="clearMessage();">Cancel message before it happens</button>
<div id="output"></div>
</pre>
<h4 id="JavaScript">JavaScript</h4>
<pre class="brush: js">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);
}
</pre>
<pre class="brush: css hidden">
#output {
padding: .5rem 0;
}
</pre>
<h4 id="Result">Result</h4>
<p>{{EmbedLiveSample('Setting_and_clearing_timeouts')}}</p>
<p>See also the <a
href="/en-US/docs/Web/API/clearTimeout#example"><code>clearTimeout()</code>
example</a>.</p>
<h2 id="Specifications">Specifications</h2>
{{Specifications}}
<h2 id="Browser_compatibility">Browser compatibility</h2>
<p>{{Compat}}</p>
<h2 id="See_also">See also</h2>
<ul>
<li>A polyfill of <code>setTimeout</code> which allows passing arguments to the callback is available in <a href="https://github.com/zloirock/core-js#settimeout-and-setinterval"><code>core-js</code></a></li>
<li>{{domxref("clearTimeout")}}</li>
<li>{{domxref("setInterval()")}}</li>
<li>{{domxref("window.requestAnimationFrame")}}</li>
<li>{{domxref("queueMicrotask()")}}</li>
</ul>