Пошук уроків, статей та іншого контенту
Керуватимете відкладеними й повторюваними операціями за допомогою таймерів браузера.
Таймери дають змогу виконати код не одразу, а через певний час або регулярно через однакові проміжки.
У браузері для цього використовують дві основні функції:
setTimeout — виконує функцію один раз після затримки;
setInterval — виконує функцію повторно через задані проміжки часу.
Час передають у мілісекундах:
1000 мс — це 1 секунда;
500 мс — це пів секунди;
60_000 мс — це 1 хвилина.
setTimeoutsetTimeout планує одноразовий виклик функції:
setTimeout(function () {
console.log("Повідомлення з'явилося через 2 секунди");
}, 2000);Стрілкова функція дає змогу записати цей приклад коротше:
setTimeout(() => {
console.log("Повідомлення з'явилося через 2 секунди");
}, 2000);Важливо: setTimeout не зупиняє виконання всієї програми. Браузер запланує функцію, а JavaScript продовжить виконувати наступні інструкції.
console.log("Початок");
setTimeout(() => {
console.log("Таймер завершився");
}, 1000);
console.log("Кінець");Результат у консолі:
Початок
Кінець
Таймер завершивсяsetTimeout повертає ідентифікатор запланованого таймера. Його можна зберегти у змінну:
const timeoutId = setTimeout(() => {
console.log("Це повідомлення");
}, 3000);Щоб скасувати таймер до його виконання, використовують clearTimeout:
const timeoutId = setTimeout(() => {
console.log("Цей код не виконається");
}, 3000);
clearTimeout(timeoutId);Скасувати таймер потрібно за тим самим ідентифікатором, який повернув setTimeout.
Після затримки можна передати додаткові аргументи у функцію:
function showGreeting(name) {
console.log(`Привіт, ${name}!`);
}
setTimeout(showGreeting, 1000, "Олено");Проте на практиці часто використовують стрілкову функцію:
const name = "Олено";
setTimeout(() => {
console.log(`Привіт, ${name}!`);
}, 1000);У цьому прикладі функція має доступ до змінної name, яка була оголошена зовні. Таку можливість забезпечує замикання.
setIntervalsetInterval повторно викликає функцію через вказаний проміжок часу:
const intervalId = setInterval(() => {
console.log("Це повідомлення з'являється кожні 2 секунди");
}, 2000);На відміну від setTimeout, інтервал продовжується, доки його явно не скасувати.
Для скасування використовують clearInterval:
const intervalId = setInterval(() => {
console.log("Повторювана дія");
}, 1000);
clearInterval(intervalId);Зазвичай інтервал зупиняють за певною умовою:
let counter = 0;
const intervalId = setInterval(() => {
counter += 1;
console.log(`Виконання №${counter}`);
if (counter === 3) {
clearInterval(intervalId);
console.log("Інтервал зупинено");
}
}, 1000);Цей код виведе повідомлення тричі, а потім зупинить інтервал.
Нижче наведено повний приклад HTML-сторінки із секундоміром. Кнопка Старт запускає відлік, Пауза зупиняє його, а Скинути повертає значення до нуля.
<!doctype html>
<html lang="uk">
<head>
<meta charset="UTF-8" />
<title>Секундомір</title>
</head>
<body>
<p id="time">0</p>
<button id="start">Старт</button>
<button id="pause">Пауза</button>
<button id="reset">Скинути</button>
<script>
const timeElement = document.querySelector("#time");
const startButton = document.querySelector("#start");
const pauseButton = document.querySelector("#pause");
const resetButton = document.querySelector("#reset");
let seconds = 0;
let intervalId = null;
function updateTime() {
timeElement.textContent = seconds;
}
startButton.addEventListener("click", () => {
// Не створюємо новий інтервал, якщо секундомір уже працює
if (intervalId !== null) {
return;
}
intervalId = setInterval(() => {
seconds += 1;
updateTime();
}, 1000);
});
pauseButton.addEventListener("click", () => {
// Зупиняємо поточний інтервал
clearInterval(intervalId);
intervalId = null;
});
resetButton.addEventListener("click", () => {
// Зупиняємо відлік і повертаємо початковий стан
clearInterval(intervalId);
intervalId = null;
seconds = 0;
updateTime();
});
</script>
</body>
</html>Зверніть увагу на перевірку:
if (intervalId !== null) {
return;
}Без неї кожне натискання кнопки Старт створювало б новий інтервал. У результаті лічильник збільшувався б кілька разів за секунду.
setTimeout замість setIntervalДля простих повторюваних дій можна використовувати setInterval. Але іноді зручніше після кожного виконання створювати новий setTimeout:
let counter = 0;
function repeatAction() {
counter += 1;
console.log(`Виконання №${counter}`);
if (counter < 3) {
setTimeout(repeatAction, 1000);
}
}
setTimeout(repeatAction, 1000);Такий підхід корисний, коли наступний запуск залежить від результату попереднього. Наприклад, якщо всередині функції виконується асинхронна операція, можна планувати наступний запуск лише після її завершення.
Порівняння:
setInterval намагається запускати функцію регулярно;
рекурсивний setTimeout дає змогу контролювати момент наступного запуску.
Затримка в setTimeout і період у setInterval є мінімальним часом очікування, а не гарантією точного запуску.
setTimeout(() => {
console.log("Функція буде запущена приблизно через 1000 мс");
}, 1000);Функція може виконатися пізніше, якщо:
браузер зайнятий виконанням іншого JavaScript-коду;
головний потік заблокований довгою операцією;
вкладка працює у фоновому режимі;
черга подій містить інші завдання.
JavaScript у браузері виконує код послідовно. Таймер лише додає функцію до черги завдань після завершення затримки. Функція виконається тоді, коли звільниться головний потік.
async-кодТаймери часто обгортають у Promise, щоб використовувати їх з await:
function wait(milliseconds) {
return new Promise((resolve) => {
setTimeout(resolve, milliseconds);
});
}
async function run() {
console.log("Початок");
await wait(1000);
console.log("Минуло 1 секунда");
}
run();Функція wait повертає проміс, який виконується після завершення таймера.
Неправильно:
setTimeout(showMessage(), 1000);У цьому випадку showMessage() виконається одразу, а результат її виклику буде передано в setTimeout.
Правильно:
setTimeout(showMessage, 1000);Або:
setTimeout(() => {
showMessage();
}, 1000);clearIntervalЯкщо більше не потрібно виконувати повторювану дію, інтервал слід зупинити:
const intervalId = setInterval(updateData, 5000);
// Коли оновлення більше не потрібне
clearInterval(intervalId);Незупинений інтервал може продовжувати виконувати код, споживати ресурси та змінювати DOM після того, як відповідний елемент уже не потрібен.
button.addEventListener("click", () => {
setInterval(() => {
console.log("Оновлення");
}, 1000);
});Кожне натискання створює ще один інтервал. Краще зберігати ідентифікатор і перевіряти, чи інтервал уже запущений.
Не рекомендується:
setTimeout("console.log('Привіт')", 1000);Передавайте функцію:
setTimeout(() => {
console.log("Привіт");
}, 1000);Це безпечніше, зрозуміліше та дає змогу використовувати змінні з поточного контексту.
Не слід використовувати кількість спрацювань setInterval як абсолютно точний вимір часу. Якщо потрібен точний час, зберігайте момент початку та обчислюйте різницю між поточним часом і ним:
const startedAt = Date.now();
const intervalId = setInterval(() => {
const elapsedSeconds = Math.floor((Date.now() - startedAt) / 1000);
console.log(`Минуло секунд: ${elapsedSeconds}`);
if (elapsedSeconds >= 5) {
clearInterval(intervalId);
}
}, 100);setTimeout виконує функцію один раз після затримки.
setInterval повторює виклик функції через заданий інтервал.
Час передають у мілісекундах.
clearTimeout скасовує таймер setTimeout.
clearInterval зупиняє таймер setInterval.
Ідентифікатор таймера потрібно зберігати, якщо його доведеться скасувати.
Таймери не блокують виконання JavaScript-коду.
Затримка таймера є мінімальною, а не гарантовано точною.
Для складніших повторюваних операцій зручно використовувати setTimeout після завершення попередньої дії.