Глиф Учебники

Как сделать таймер: setInterval и обратный отсчёт

Справочник · JavaScript · 1 минута чтения

Повторять действие через равные промежутки умеет setInterval, остановить его — clearInterval. Обратный отсчёт от трёх в Node.js:

JavaScript
let seconds = 3;

const timerId = setInterval(() => {
  console.log(seconds);
  seconds--;
  if (seconds === 0) {
    clearInterval(timerId);
    console.log("Время вышло!");
  }
}, 1000);
Вывод
3
2
1
Время вышло!

Таймер на странице

Разметка — табло и две кнопки:

HTML
<p id="clock">05:00</p>
<button id="start">Старт</button>
<button id="stop">Стоп</button>

Код:

JavaScript
const clock = document.querySelector("#clock");
let left = 5 * 60;
let timerId = null;

function show() {
  const m = String(Math.floor(left / 60)).padStart(2, "0");
  const s = String(left % 60).padStart(2, "0");
  clock.textContent = `${m}:${s}`;
}

document.querySelector("#start").addEventListener("click", () => {
  if (timerId !== null || left === 0) {
    return;
  }
  timerId = setInterval(() => {
    left--;
    show();
    if (left === 0) {
      clearInterval(timerId);
      timerId = null;
      clock.textContent = "Время вышло!";
    }
  }, 1000);
});

document.querySelector("#stop").addEventListener("click", () => {
  clearInterval(timerId);
  timerId = null;
});

«Старт» запускает отсчёт пяти минут, «Стоп» ставит его на паузу, повторный «Старт» продолжает с того же места. padStart(2, "0") дописывает ноль слева: 5 → 05.

Проверка timerId !== null в начале обработчика важна: без неё каждое нажатие «Старт» запускает ещё один интервал, и время бежит вдвое, втрое быстрее, а «Стоп» останавливает только последний.

Почему таймер отстаёт

setInterval не обещает точности: вызов может случиться позже, если браузер занят. А в неактивной вкладке браузеры нарочно вызывают таймеры реже, чтобы экономить заряд. За несколько минут счётчик «каждую секунду минус один» заметно отстаёт от настоящих часов.

Для точного отсчёта запомните момент окончания и на каждом шаге считайте, сколько до него осталось:

JavaScript
const clock = document.querySelector("#clock");
const end = Date.now() + 5 * 60 * 1000;

const timerId = setInterval(() => {
  const left = Math.max(0, Math.round((end - Date.now()) / 1000));
  const m = String(Math.floor(left / 60)).padStart(2, "0");
  const s = String(left % 60).padStart(2, "0");
  clock.textContent = `${m}:${s}`;
  if (left === 0) {
    clearInterval(timerId);
  }
}, 250);

Date.now() — текущее время в миллисекундах. Даже если какой-то вызов опоздал, следующий покажет верное время. Интервал здесь короче секунды, чтобы табло не перескакивало через цифры.

Секундомер

Для секундомера — то же самое наоборот: запомните момент старта и выводите, сколько прошло: Math.floor((Date.now() - start) / 1000) секунд.