На этой странице

setTimeout(): void

При написании JavaScript-кода вам может понадобиться отложить выполнение функции.

Этим занимается setTimeout. Вы указываете функцию-колбэк, которую нужно выполнить позже, и значение, выражающее, насколько позже её запустить, в миллисекундах:

setTimeout(() => {
  // выполнится через 2 секунды
}, 2000);

setTimeout(() => {
  // выполнится через 50 миллисекунд
}, 50);

Этот синтаксис определяет новую функцию. Внутри неё можно вызвать любую другую функцию либо передать имя существующей функции и набор параметров:

const myFunction = (firstParam, secondParam) => {
  // делаем что-то
};

// выполнится через 2 секунды
setTimeout(myFunction, 2000, firstParam, secondParam);

setTimeout возвращает экземпляр Timeout в Node.js, тогда как в браузерах он возвращает числовой ID таймера. Этот объект или ID можно использовать, чтобы отменить запланированное выполнение функции:

const timeout = setTimeout(() => {
  // должно выполниться через 2 секунды
}, 2000);

// я передумал
clearTimeout(timeout);

Если задать задержку таймаута равной 0, функция-колбэк выполнится как можно скорее, но после выполнения текущей функции:

setTimeout(() => {
  console.log('after ');
}, 0);

console.log(' before ');

Этот код напечатает

before
after

Это особенно полезно, чтобы не блокировать CPU на интенсивных задачах и дать другим функциям выполниться во время тяжёлого вычисления, ставя функции в очередь планировщика.

Некоторые браузеры (IE и Edge) реализуют метод setImmediate() с ровно такой же функциональностью, но он нестандартен и недоступен в других браузерах. При этом в Node.js это стандартная функция.

setInterval(): void

setInterval — функция, похожая на setTimeout, с одним отличием: вместо однократного запуска колбэка она будет запускать его бесконечно, через указанный вами интервал времени (в миллисекундах):

setInterval(() => {
  // выполняется каждые 2 секунды
}, 2000);

Функция выше выполняется каждые 2 секунды, пока вы не скажете ей остановиться, используя clearInterval и передав ему id интервала, который вернул setInterval:

const timeout = setInterval(() => {
  // выполняется каждые 2 секунды
}, 2000);

clearInterval(timeout);

Часто clearInterval вызывают внутри колбэка setInterval, чтобы тот сам решал, стоит ли ему выполниться снова или остановиться. Например, этот код что-то выполняет, пока App.somethingIWait не примет значение arrived:

const interval = setInterval(() => {
  if (App.somethingIWait === 'arrived') {
    clearInterval(interval);
  }
  // иначе делаем что-то
}, 100);

setInterval запускает функцию каждые n миллисекунд, не учитывая, когда функция завершила своё выполнение.

Если функция всегда занимает одно и то же время, всё хорошо:

0         1000        2000        3000
|          |           |           |
|          |           |           |
|       [██████████]   |           |
|       [exe script]   |           |
|       [██████████]   |           |
|          |  [██████████]         |
|          |  [exe script]         |
|          |  [██████████]         |
|          |           |  [██████████]
|          |           |  [exe script]
|          |           |  [██████████]
|__________|___________|___________|____

Возможно, функция занимает разное время выполнения, например в зависимости от условий сети:

0         1000        2000        3000
|          |           |           |
|          |           |           |
|       [██████████]   |           |
|       [exe script]   |           |
|       [██████████]   |           |
|          |  [████████████████████]
|          |  [  execute script    ]
|          |  [████████████████████]
|          |           |     [██████████]
|          |           |     [exe script]
|          |           |     [██████████]
|__________|___________|___________|____

А может быть, одно длинное выполнение накладывается на следующее:

0         1000        2000        3000        4000
|          |           |           |           |
|     [████████████████████]       |           |
|     [    execute script  ]       |           |
|     [████████████████████]       |           |
|          [███████████████████████████]       |
|          [      execute script       ]       |
|          [███████████████████████████]       |
|          |           |           [██████████████]
|          |           |           [execute script]
|          |           |           [██████████████]
|__________|___________|___________|___________|__

Чтобы этого избежать, можно запланировать рекурсивный setTimeout, вызываемый по завершении функции-колбэка:

const myFunction = () => {
  // делаем что-то

  setTimeout(myFunction, 1000);
};

setTimeout(myFunction, 1000);

чтобы получить такой сценарий:

0         1000         2000        3000
|          |            |           |
|     [█████████████]   |    [█████████████]
|     [ exec script ]>──1s──<[ exec script ]
|     [█████████████]   |    [█████████████]
|          |            |           |
|__________|____________|___________|__________

setTimeout и setInterval доступны в Node.js через модуль Timers.

Node.js также предоставляет setImmediate(), который планирует выполнение колбэка в фазе check event loop. В отличие от setTimeout(() => {}, 0), в общем случае это не эквивалентно, потому что их колбэки выполняются в разных фазах event loop, и порядок их выполнения зависит от контекста выполнения.