Переклад цієї статті ще триває.

 
Метод setTimeout(), що належить об'єкту WindowOrWorkerGlobalScope, та наслідується від window.setTimeout,  встановлює таймер, що виконує функцію або вказаний фрагмент коду один раз, щойно спливе заданий час.
 

Синтаксис

var timeoutID = window.setTimeout(func[, delay, param1, param2, ...]);
var timeoutID = window.setTimeout(code[, delay]);

Параметри

func
function котру необхідно виконати після того, як вийде заданий час.
code
Опційний синтаксис, котрий дозволяє задавати рядок замість функції, котра компілюється і виконується при спрацюванні таймера. Використання цього синтаксису не рекомендовано з тих же ж причин, котрі роблять застосування eval() загрозою безпеці.
delay Optional
 
Час у мілісекундах (тисячних секунди), котрий таймер має зачекати перед тим, як виконати вказану функцію або код. Якщо цей параметр пропустити, буде використано значення 0. Варто зазначити, що справжній час затримки, може бути довшим. Дивіться розділ Причини, з яких затримка є фактично довшою ніж задано
param1, ..., paramN Optional
Додаткові параметри, що передаються до func або code, щойно час таймера спливе.

Зверніть увагу:  Internet Explorer 9 та більш ранні версії не підтримують додаткові параметри. Застосовуйте поліфіл, щобл уможливити цей функціонал (див. розділ Callback arguments).  

Значення, що повертається


Після виклику setTimeout(), повертається timeoutID  - це не нульове цифрове значення, що використовується для ідентифікації створеного таймера. Цей ідентифікатор можна передати як параметр до Window.clearTimeout() щоб відмінити таймер.

Корисно знати, що setTimeout() та setInterval() використовують спільну колекцію ID ідентифікаторів, а також що  clearTimeout() та clearInterval() технічно можуть бути взаємозамінними. Тим не меньше, задля ясності, варто завжди зіставляти їх, аби не допускати помилок під час розробка коду. 

Приклад

У наступному прикладі створено дві кнопки на веб сторінці, що прив'язані до setTimeout() та clearTimeout() процесів. Після натискання на першу кнопку встановлюється таймер, що викликає діалогове вікно alert через дві секунди та зберігає ID таймера для подальшого використання у clearTimeout(). За бажанням ви можете відмінити цей таймер, якщо натисните другу кнопку.

HTML код

<p>Live Example</p>
<button onclick="delayedAlert();">Відобразити діалогове вікно alert через дві секунди.</button>
<p></p>
<button onclick="clearAlert();">Відмінити відображення діалогового вікна.</button>

JavaScript код

var timeoutID;

function delayedAlert() {
  timeoutID = window.setTimeout(slowAlert, 2000);
}

function slowAlert() {
  alert("Це було дійсно повільно!");
}

function clearAlert() {
  window.clearTimeout(timeoutID);
}

Результат

Дивіться також 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');
}())

Фікс для IE

Якщо вам потрібен фікс, який не впливатиме на роботу жодного іншого мобільного чи десктопного браузера, окрім 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);
};
Зверніть увагу:  Подібний підхід дозволяє передавати будь-яку кількість аргументів у колбек функцію таймерів навіть для IE. Таким чином, цей спосіб може також бути використаний як поліфіл. Перегляньте параграф Callback arguments .

Випробування нового підхода:

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
Зверніть увагу:  JavaScript 1.8.5 впровадив метод   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

Примітки

Таймер можна скасувати за допомогою Window.clearTimeout(). Щоб викликати функцію повторно (наприклад, через кожні N мілісекунди), використовуйте  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 string literals

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.

Nested timeouts forced to >=4ms

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 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2), the minimum timeout value for nested timeouts was 10 ms.

To implement a 0 ms timeout in a modern browser, you can use window.postMessage() as described here.

Timeouts in inactive tabs clamped to >=1000ms

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 AudioContext is actively playing sound. Firefox 51 further amends this such that background tabs are no longer throttled if an 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.

Late timeouts

In addition to "clamping", the timeout can also fire later when the page (or the OS/browser itself) is busy with other tasks

Maximum delay value

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.

Specifications

Specification Status Comment
HTML Living Standard
The definition of 'WindowTimers.setTimeout()' in that specification.
Living Standard Initial definition (DOM Level 0)

Browser compatibility

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 1.0 1.0 (1.7 or earlier) 4.0 4.0 1.0
Supports parameters for callback[1] (Yes) (Yes) 10.0 (Yes) (Yes)
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support 1.0 1.0 1.0 (1) 6.0 6.0 1.0
Supports parameters for callback[1] ? ? ? ? ? ?

[1] Whether it supports the optional parameters when in its first form or not.

See also

Мітки документа й учасники

Зробили внесок у цю сторінку: Rozelin, Kamilius
Востаннє оновлена: Rozelin,