--- title: WindowTimers.setTimeout() slug: Web/API/WindowTimers/setTimeout translation_of: Web/API/WindowOrWorkerGlobalScope/setTimeout ---
setTimeout()
, що належить об'єкту {{domxref("WindowOrWorkerGlobalScope")}}, та наслідується від window.setTimeout, встановлює таймер, що виконує функцію або вказаний фрагмент коду один раз, щойно спливе заданий час.var timeoutID = window.setTimeout(func[, delay, param1, param2, ...]); var timeoutID = window.setTimeout(code[, delay]);
func
code
delay
{{optional_inline}}param1, ..., paramN
{{optional_inline}}Зверніть увагу: Internet Explorer 9 та більш ранні версії не підтримують додаткові параметри. Застосовуйте поліфіл, щобл уможливити цей функціонал (див. розділ Callback arguments).
Після виклику setTimeout()
, повертається timeoutID
- це не нульове цифрове значення, що використовується для ідентифікації створеного таймера. Цей ідентифікатор можна передати як параметр до {{domxref("Window.clearTimeout()")}} щоб відмінити таймер.
Корисно знати, що setTimeout()
та {{domxref("WindowTimers.setInterval", "setInterval()")}} використовують спільну колекцію ID ідентифікаторів, а також що clearTimeout()
та {{domxref("WindowTimers.clearInterval", "clearInterval()")}} технічно можуть бути взаємозамінними. Тим не менше, задля ясності, варто завжди зіставляти їх, аби не допускати помилок під час розробки коду.
У наступному прикладі створено дві кнопки на веб сторінці, що прив'язані до setTimeout()
та clearTimeout()
процесів. Після натискання на першу кнопку встановлюється таймер, що викликає діалогове вікно alert через дві секунди та зберігає ID таймера для подальшого використання у clearTimeout()
. За бажанням ви можете відмінити цей таймер, якщо натисните другу кнопку.
<p>Live Example</p> <button onclick="delayedAlert();">Відобразити діалогове вікно alert через дві секунди.</button> <p></p> <button onclick="clearAlert();">Відмінити відображення діалогового вікна.</button>
var timeoutID; function delayedAlert() { timeoutID = window.setTimeout(slowAlert, 2000); } function slowAlert() { alert("Це було дійсно повільно!"); } function clearAlert() { window.clearTimeout(timeoutID); }
{{EmbedLiveSample('Example', 'Приклад')}}
Дивіться також clearTimeout()
example.
Якщо вам необхідно передати один чи декілька аргументів до колбек функції, а також потрібно, щоб цей функціонал працював у браузерах, що не підтримують передачу додаткових аргументів для setTimeout()
чи setInterval()
(наприклад, версії Internet Explorer 9 чи нижче), ви можете застосувати цей поліфіл, який активує стандартну HTML5 функціональність. Просто додайте цей код на початку вашого скрипта:
/*\ |*| |*| Polyfill which enables the passage of arbitrary arguments to the |*| callback functions of JavaScript timers (HTML5 standard syntax). |*| |*| https://developer.mozilla.org/en-US/docs/DOM/window.setInterval |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay[, param1, param2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, param1, param2, ...]); |*| var intervalID = window.setInterval(code, delay); |*| \*/ (function() { setTimeout(function(arg1) { if (arg1 === 'test') { // feature test is passed, no need for polyfill return; } var __nativeST__ = window.setTimeout; window.setTimeout = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function() { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; }, 0, 'test'); var interval = setInterval(function(arg1) { clearInterval(interval); if (arg1 === 'test') { // feature test is passed, no need for polyfill return; } var __nativeSI__ = window.setInterval; window.setInterval = function(vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */ ) { var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function() { vCallback.apply(null, aArgs); } : vCallback, nDelay); }; }, 0, 'test'); }())
Якщо вам потрібен фікс, який не впливатиме на роботу жодного іншого мобільного чи десктопного браузера, окрім IE9 та нижче, ви можете скористатись умовними коментарями JavaScript:
/*@cc_on // conditional IE < 9 only fix @if (@_jscript_version <= 9) (function(f){ window.setTimeout=f(window.setTimeout); window.setInterval=f(window.setInterval); })(function(f){return function(c,t){var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)}}); @end @*/
Або використати умовні коментарі HTML для IE9 та нижче:
<!--[if lte IE 9]><script> (function(f){ window.setTimeout=f(window.setTimeout); window.setInterval=f(window.setInterval); })(function(f){return function(c,t){ var a=[].slice.call(arguments,2);return f(function(){c instanceof Function?c.apply(this,a):eval(c)},t)} }); </script><![endif]-->
Ще одне можливе рішення - використання анонімної функції для виклику колбека, але це вартісне рішення. Приклад:
var intervalID = setTimeout(function() { myFunc("one", "two", "three"); }, 1000);
Приклад, наведений вище, може бути також написаний за допомогою arrow function:
var intervalID = setTimeout(() => { myFunc("one", "two", "three"); }, 1000);
Ще одне рішення - використання function's bind
. Приклад:
setTimeout(function(arg1){}.bind(undefined, 10), 1000);
this
"Коли ви передаєте до setTimeout()
метод або будь-яку іншу функцію, ймовірно вона буде викликана не з тим значенням this
, на яке ви очікуєте. Ця проблема детально описана у JavaScript reference.
Код, що виконується всередині setTimeout()
, викликається із іншого контекста виконання (execution context), ніж у функції, яка викликала setTimeout
. До функції, яку викликають всередині setTimeout
застосовуються звичайні правила призначення this
. І, якщо ви не встановили this
під час виклику або за допомогою bind
, його значенням за замовчуванням буде об'єкт global
(або window
) у нестрогому режимі, або undefined
у строгому режимі. Значення this
буде іншим, аніж у функції, яка викликала setTimeout
. Розгляньте наступний приклад:
myArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) { alert(arguments.length > 0 ? this[sProperty] : this); }; myArray.myMethod(); // prints "zero,one,two" myArray.myMethod(1); // prints "one"
Приклад вище працює тому, що myMethod
викликано, як метод масиву myArray
. Тому його this
дорівнює myArray
, а значення this[sProperty]
всередині метода дорівнює myArray[sProperty]
. Тим не менше, у наступному прикладі:
setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1.5 seconds
Метод myArray.myMethod
передано до setTimeout
, як звичайну функцію, якій не задано значення this
. І коли вона викликається, її this
за замовчуванням дорівнює об'єкту window
. У setTimeout
неможливо передати this
аргументом, як, наприклад, у методи Array (forEach, reduce, тощо), або через використання call
, як показано у прикладі нижче:
setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object" setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error
Типовий спосіб вирішення цієї проблеми - використання функції обгортки, яка встановлює this
із необхідним значенням:
setTimeout(function(){myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds setTimeout(function(){myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds
Стрілочна функція також є прийнятною альтернативою:
setTimeout(() => {myArray.myMethod()}, 2000); // prints "zero,one,two" after 2 seconds setTimeout(() => {myArray.myMethod('1')}, 2500); // prints "one" after 2.5 seconds
Ще одне можливе рішення проблеми this
- замінити нативні глобальні функції setTimeout()
та setInterval()
кастомними функціями, які можуть приймати об'єкт this
і застосовувати його у колбек функції, використовуючи Function.prototype.call
. Наприклад:
// Enable setting 'this' in JavaScript timers var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () { vCallback.apply(oThis, aArgs); } : vCallback, nDelay); }; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) { var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () { vCallback.apply(oThis, aArgs); } : vCallback, nDelay); };
Випробування нового підхода:
myArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) { alert(arguments.length > 0 ? this[sProperty] : this); }; setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but... setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2.5 seconds
Function.prototype.bind()
, який встановлює значення this
для кожного виклику вказаної функції. Це допомагає уникнути використання функції обгортки для призначення this
колбека.Приклад використання bind()
:
myArray = ["zero", "one", "two"]; 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, 1000); // still prints "zero,one,two" after 1 second because of the binding setTimeout(myBoundMethod, 1500, "1"); // prints "one" after 1.5 seconds
Таймер можна скасувати за допомогою {{domxref("Window.clearTimeout()")}}. Щоб викликати функцію повторно (наприклад, через кожні N мілісекунди), використовуйте {{domxref("Window.setInterval()")}}.
Важливо пам'ятати, що функція або фрагмент коду не можуть бути виконані, допоки не буде завершено поток функції, яка викликала setTimeout()
. Наприклад.
function foo(){ console.log('foo has been called'); } setTimeout(foo, 0); console.log('After setTimeout');
Виведе в консоль:
After setTimeout foo has been called
Тому що, навіть не зважаючи на те, що setTimeout
було викликано із нульовою затримкою, вона переміщується у чергу і її виконання відбудеться у найближчому наступному циклі, тобто не відразу. Код, що в данний момент виконується, повинен бути завершений. Тільки після цього функції, переміщені в чергу, будуть виконані. Тому порядок виконання може бути іншим, аніж очікувалось.
Passing a string instead of a function to setTimeout()
suffers from the same hazards as using eval.
// Recommended window.setTimeout(function() { alert("Hello World!"); }, 500); // Not recommended window.setTimeout("alert('Hello World!');", 500);
A string passed to setTimeout
is evaluated in the global context, so local symbols in the context where setTimeout()
was called will not be available when the string is evaluated as code.
There are a number of reasons why a timeout may take longer to fire than anticipated. This section describes the most common reasons.
Historically browsers implement setTimeout()
"clamping": successive setTimeout()
calls with delay
smaller than the "minimum delay" limit are forced to use at least the minimum delay. The minimum delay, DOM_MIN_TIMEOUT_VALUE
, is 4 ms (stored in a preference in Firefox: dom.min_timeout_value
), with a DOM_CLAMP_TIMEOUT_NESTING_LEVEL
of 5.
In fact, 4 ms is specified by the HTML5 spec and is consistent across browsers released in 2010 and onward. Prior to {{geckoRelease("5.0")}}, the minimum timeout value for nested timeouts was 10 ms.
To implement a 0 ms timeout in a modern browser, you can use {{domxref("window.postMessage()")}} as described here.
To reduce the load (and associated battery usage) from background tabs, timeouts are often clamped to firing no more often than once per second (1000 ms) in inactive tabs.
Firefox implements this behavior since version 5 (see {{bug(633421)}}, the 1000ms constant can be tweaked through the dom.min_background_timeout_value
preference). Chrome implements this behavior since version 11 (crbug.com/66078).
Firefox for Android uses a timeout value of 15 minutes for background tabs since {{bug(736602)}} in Firefox 14, and background tabs can also be unloaded entirely.
Firefox 50 no longer throttles background tabs if a Web Audio API {{domxref("AudioContext")}} is actively playing sound. Firefox 51 further amends this such that background tabs are no longer throttled if an {{domxref("AudioContext")}} is present in the tab at all, even if no sound is being played. These resolve a number of issues with apps which play note-based music not being able to time or synchronize the music properly when the tab is in the background.
In addition to "clamping", the timeout can also fire later when the page (or the OS/browser itself) is busy with other tasks
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 2147483647, resulting in the timeout being executed immediately.
Specification | Status | Comment |
---|---|---|
{{SpecName("HTML WHATWG", "webappapis.html#dom-settimeout", "WindowTimers.setTimeout()")}} | {{Spec2("HTML WHATWG")}} | Initial definition (DOM Level 0) |
{{CompatibilityTable}}
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Basic support | 1.0 | {{CompatGeckoDesktop("1")}} | 4.0 | 4.0 | 1.0 |
Supports parameters for callback[1] | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} | 10.0 | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} |
Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Basic support | 1.0 | 1.0 | {{CompatGeckoMobile("1")}} | 6.0 | 6.0 | 1.0 |
Supports parameters for callback[1] | {{CompatUnknown}} | {{CompatUnknown}} | {{CompatUnknown}} | {{CompatUnknown}} | {{CompatUnknown}} | {{CompatUnknown}} |
[1] Whether it supports the optional parameters when in its first form or not.