setTimeout, setInterval и колбэки
Первые инструменты асинхронности в JavaScript — таймеры. Они позволяют выполнить код через определённое время или повторять его с интервалом. Разберём как они работают, и почему злоупотребление ими — путь к «callback hell».
⏱️ setTimeout — выполнить один раз через N миллисекунд
setTimeout(функция, задержка) — запускает функцию один раз через указанное количество миллисекунд. 1000 мс = 1 секунда. Браузер ставит таймер, продолжает выполнять остальной код, и когда таймер истечёт — вызывает нашу функцию.
// Через 2 секунды выводим сообщение
setTimeout(() => {
console.log('2 секунды прошло!');
}, 2000);
console.log('Этот код выполнится РАНЬШЕ, хотя написан после!');
// Вывод:
// Этот код выполнится РАНЬШЕ, хотя написан после!
// (через 2 сек) 2 секунды прошло!
⚠️ Важно: setTimeout не «ставит программу на паузу». Браузер продолжает выполнять следующие строки кода. Колбэк вызовется позже, когда Call Stack опустеет.
setTimeout возвращает ID таймера — число. С помощью него можно отменить таймер до истечения:
const timerId = setTimeout(() => {
console.log('Это НЕ выведется');
}, 5000);
// Отменяем таймер до того, как он сработал
clearTimeout(timerId);
console.log('Таймер отменён');
🔄 setInterval — повторять каждые N миллисекунд
setInterval(функция, интервал) — вызывает функцию снова и снова с указанным интервалом. В отличие от setTimeout, который срабатывает один раз, setInterval продолжает работать, пока его не остановишь.
let count = 0;
const intervalId = setInterval(() => {
count++;
console.log('Прошло секунд:', count);
if (count >= 5) {
clearInterval(intervalId); // останавливаем после 5 итераций
console.log('Готово!');
}
}, 1000);
🚨 Всегда останавливай setInterval! Если не вызвать clearInterval(), таймер будет работать вечно — даже после ухода со страницы (в SPA). Это приводит к утечкам памяти.
Один раз через N мс
Отменить: clearTimeout(id)
Повторять каждые N мс
Остановить: clearInterval(id)
💻 Практические примеры
⏳ Таймер обратного отсчёта
let seconds = 10;
const display = document.querySelector('#countdown');
display.textContent = seconds;
const timer = setInterval(() => {
seconds--;
display.textContent = seconds;
if (seconds <= 0) {
clearInterval(timer);
display.textContent = 'Время вышло!';
}
}, 1000);
🕐 Живые часы
function updateClock() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const mins = String(now.getMinutes()).padStart(2, '0');
const secs = String(now.getSeconds()).padStart(2, '0');
document.querySelector('#clock').textContent =
`${hours}:${mins}:${secs}`;
}
// Сразу показываем, потом обновляем каждую секунду
updateClock();
setInterval(updateClock, 1000);
😱 Callback Hell — ад вложенных колбэков
Когда одна асинхронная операция должна следовать за другой, возникает соблазн вложить колбэк в колбэк. Три-четыре уровня вложенности — и код превращается в «рождественскую ёлку» или «ад колбэков»:
// Плохо: callback hell
setTimeout(() => {
console.log('Шаг 1');
setTimeout(() => {
console.log('Шаг 2');
setTimeout(() => {
console.log('Шаг 3');
setTimeout(() => {
console.log('Шаг 4'); // ...и так далее
}, 1000);
}, 1000);
}, 1000);
}, 1000);
💡 Именно для решения этой проблемы в JavaScript появились Промисы (Promise) и синтаксис async/await. Они превращают «ёлку» в линейный читаемый код. Разберём их в следующих уроках.
Callback hell — это не просто эстетическая проблема. Такой код: сложно читать, сложно дебажить, сложно добавлять обработку ошибок, сложно тестировать. Именно поэтому современный JS-код почти не использует глубокую вложенность колбэков.
✅ Итоги урока
setTimeout(fn, ms)— выполнить функцию один раз через ms миллисекундsetInterval(fn, ms)— повторять функцию каждые ms миллисекундclearTimeout(id)иclearInterval(id)— отменить/остановить таймер- setTimeout не блокирует выполнение — остальной код продолжает работать
- Всегда сохраняй ID таймера и останавливай setInterval — иначе утечка памяти
- Callback Hell — глубокая вложенность колбэков — делает код нечитаемым
- Для решения callback hell в JS появились Promise и async/await
В следующем уроке разберём Промисы — элегантный способ работы с асинхронным кодом. 🚀
setTimeout, setInterval и колбэки
7 вопросов