1. setTimeout: «Сделай это потом!»
В реальном мире всё происходит во времени: чайник кипит, пока вы не выключите, а кот приходит к вам за едой ровно в 7 утра (и не минутой позже!). В веб-разработке тоже бывают ситуации, когда нужно что-то делать через определённый промежуток времени или повторять действие снова и снова.
Примеры из жизни веба:
- Показать всплывающее уведомление через 2 секунды после загрузки страницы.
- Менять цвет фона каждую секунду (да, это немного раздражает, но зато весело!).
- Скрывать подсказку через 5 секунд после показа.
- Анимация: делать плавные изменения, например, мигание текста или появление/исчезновение элементов.
Для этого в JavaScript есть два главных инструмента: setTimeout и setInterval. Сейчас разберёмся, что это, как работает, и как с их помощью можно оживить вашу страницу.
Что такое setTimeout?
setTimeout — это команда, которая говорит браузеру: «Выполни вот этот код через N миллисекунд». То есть, действие произойдёт один раз, с задержкой.
Синтаксис:
setTimeout(функция, задержка в мс)
- функция — что выполнить (можно передать анонимную функцию или ссылку на функцию).
- задержка в мс — через сколько миллисекунд выполнить (1000 мс = 1 секунда).
Простой пример
Пусть мы хотим, чтобы через 2 секунды после клика на кнопку она стала красной.
<button id="myBtn">Нажми меня</button>
const btn = document.getElementById('myBtn');
btn.addEventListener('click', function() {
setTimeout(function() {
btn.style.backgroundColor = 'red';
}, 2000); // 2000 мс = 2 секунды
});
Как это работает:
- Пользователь кликает на кнопку.
- Внутри обработчика события запускается таймер.
- Через 2 секунды кнопка становится красной.
Можно ли отменить setTimeout?
Иногда бывает, что пользователь передумал, и действие уже не нужно. Для этого setTimeout возвращает специальный идентификатор таймера. Его можно использовать с функцией clearTimeout.
let timerId = setTimeout(function() {
alert('Бум!');
}, 5000);
// А если вдруг передумали:
clearTimeout(timerId);
2. setInterval: «Делай это снова и снова!»
Что такое setInterval?
setInterval — это как будильник, который звонит каждые N миллисекунд: действие будет повторяться до тех пор, пока вы его не остановите.
Синтаксис:
setInterval(функция, интервал в мс)
- функция — что выполнять.
- интервал в мс — как часто выполнять (1000 мс = 1 секунда).
Пример: мигающий текст
Пусть у нас есть надпись, которая должна мигать (менять цвет) каждую секунду.
<p id="blink">Я мигаю!</p>
const blink = document.getElementById('blink');
let isRed = false;
setInterval(function() {
if (isRed) {
blink.style.color = 'black';
} else {
blink.style.color = 'red';
}
isRed = !isRed;
}, 1000); // Каждую секунду
Как остановить setInterval?
Как и в случае с setTimeout, setInterval возвращает идентификатор. Чтобы остановить повторение, используйте clearInterval(id).
let intervalId = setInterval(function() {
console.log('Тик!');
}, 1000);
// Остановить через 5 секунд
setTimeout(function() {
clearInterval(intervalId);
console.log('Будильник выключен!');
}, 5000);
3. Практика: оживляем наше приложение
Давайте поработаем с реальным примером и добавим в наше учебное приложение новый функционал: пусть у нас есть блок с подсказкой, который появляется при клике на кнопку и автоматически исчезает через 3 секунды. А ещё добавим кнопку, которая будет менять цвет своего фона каждую секунду, пока пользователь не нажмёт «Стоп».
Задача 1: Показ и скрытие подсказки через setTimeout
HTML:<button id="showHint">Показать подсказку</button>
<div id="hint" style="display: none; background: #ffd;">Это подсказка!</div>
JS:
const showHintBtn = document.getElementById('showHint');
const hint = document.getElementById('hint');
showHintBtn.addEventListener('click', function() {
hint.style.display = 'block'; // Показываем подсказку
// Скрываем через 3 секунды
setTimeout(function() {
hint.style.display = 'none';
}, 3000);
});
Что происходит:
Клик — подсказка появляется.
Через 3 секунды — исчезает.
Задача 2: Мигающая кнопка с остановкой через clearInterval
HTML:<button id="startBlink">Начать мигать</button>
<button id="stopBlink">Стоп</button>
JS:
const startBlinkBtn = document.getElementById('startBlink');
const stopBlinkBtn = document.getElementById('stopBlink');
let blinkIntervalId = null;
let isYellow = false;
startBlinkBtn.addEventListener('click', function() {
// Если уже мигает — ничего не делаем
if (blinkIntervalId !== null) return;
blinkIntervalId = setInterval(function() {
startBlinkBtn.style.backgroundColor = isYellow ? '' : 'yellow';
isYellow = !isYellow;
}, 500);
});
stopBlinkBtn.addEventListener('click', function() {
clearInterval(blinkIntervalId);
blinkIntervalId = null;
startBlinkBtn.style.backgroundColor = '';
});
Как это работает:
Нажали «Начать мигать» — кнопка мигает жёлтым.
Нажали «Стоп» — мигать перестаёт, цвет сбрасывается.
4. Как работает setTimeout и setInterval внутри браузера
Важный факт:
JavaScript в браузере работает в одном потоке. Это значит, что пока ваш код выполняется, браузер не может делать ничего другого. Таймеры не гарантируют точную задержку до миллисекунды — если в этот момент выполняется какой-то долгий скрипт, таймер подождёт, пока поток освободится.
Пример:
Если поставить setTimeout(..., 1000), а в это время запустить тяжёлый цикл на 2 секунды, таймер сработает только после окончания цикла.
Мораль:
Не используйте тяжёлые операции в одном потоке, если вам важна точная анимация или отзывчивость интерфейса. Таймеры — это не гарантия точного времени, а скорее «минимальная задержка».
5. Вложенные и повторяющиеся таймеры: что выбрать?
Когда использовать setTimeout, а когда setInterval?
- Если действие нужно выполнить только один раз через время — setTimeout.
- Если действие нужно выполнять много раз с одинаковым интервалом — setInterval.
- Если нужен «пауза между действиями», а не «строго через N мс, даже если код не успел» — можно сделать «рекурсивный setTimeout»:
function tick() {
console.log('Тик!');
setTimeout(tick, 1000);
}
tick();
Этот подход удобен, если внутри вашей функции может быть разное время выполнения, и вы хотите, чтобы пауза считалась после окончания работы функции, а не строго по расписанию.
6. Типичные ошибки и нюансы при работе с таймерами
Ошибка №1: Не сохраняется идентификатор таймера
Часто новички пишут так:
setInterval(function() { ... }, 1000);
// ... а потом пытаются сделать clearInterval(), но не знают id!
Если не сохранить возвращаемое значение, вы не сможете остановить таймер. Всегда сохраняйте id в переменную.
Ошибка №2: Таймеры плодятся как кролики
Если пользователь может многократно запускать таймер (например, кликая «Начать мигание»), а вы не проверяете, не запущен ли он уже, — получите кучу таймеров, которые будут конкурировать друг с другом. Перед запуском нового таймера убедитесь, что старый остановлен.
Ошибка №3: Забыли очистить таймер
Если вы не вызвали clearTimeout или clearInterval при уходе со страницы или при скрытии элемента, таймер продолжит работать и может вызывать ошибки или утечки памяти.
Ошибка №4: setTimeout с нулевой задержкой
Иногда пишут setTimeout(fn, 0), думая, что это мгновенно. На самом деле, это значит «выполни после текущей очереди событий». Это полезно для некоторых трюков, но не стоит ожидать, что код сработает прямо сейчас.
Ошибка №5: Таймеры внутри циклов
Если вы запускаете таймеры в цикле, не забывайте про замыкания и область видимости переменных. Часто встречается ситуация, когда все таймеры ссылаются на одну и ту же переменную (например, счетчик цикла), и все действия происходят с последним значением.
Ошибка №6: setInterval не гарантирует точный интервал
Если внутри функции, которую вы передали в setInterval, есть тяжёлая операция, следующий запуск может произойти с задержкой. Для анимаций (особенно плавных) лучше использовать requestAnimationFrame, но это тема для следующих лекций.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ