JavaScript & TypeScriptМодуль 5: Асинхронность
Таймеры
setTimeout, setInterval и requestAnimationFrame
Цель урока
В этом уроке ты научишься:
- Откладывать выполнение кода
- Создавать повторяющиеся действия
- Отменять таймеры
setTimeout
Выполняет функцию один раз через указанное время:
// setTimeout(callback, delay, ...args)
setTimeout(() => {
console.log("Прошло 2 секунды");
}, 2000);
// С аргументами
setTimeout((name, age) => {
console.log(`${name}, ${age} лет`);
}, 1000, "Иван", 25);Отмена таймера
let timerId = setTimeout(() => {
console.log("Это не выполнится");
}, 5000);
// Отменяем до выполнения
clearTimeout(timerId);setInterval
Выполняет функцию регулярно через указанный интервал:
let count = 0;
let intervalId = setInterval(() => {
count++;
console.log("Счётчик: " + count);
if (count >= 5) {
clearInterval(intervalId);
console.log("Остановлено");
}
}, 1000);Проблема накопления
// Если функция выполняется дольше интервала,
// вызовы накапливаются
setInterval(() => {
// Тяжёлая операция на 2 секунды
// при интервале 1 секунда
}, 1000);Решение — вложенный setTimeout
let count = 0;
function tick() {
count++;
console.log("Счётчик: " + count);
if (count < 5) {
setTimeout(tick, 1000);
}
}
setTimeout(tick, 1000);Минимальная задержка
// Браузер гарантирует минимум ~4мс для вложенных таймеров
setTimeout(() => {
setTimeout(() => {
setTimeout(() => {
setTimeout(() => {
setTimeout(() => {
// Здесь задержка уже ~4мс минимум
}, 0);
}, 0);
}, 0);
}, 0);
}, 0);Нулевая задержка
setTimeout(fn, 0) не означает "немедленно". Callback попадает в очередь макрозадач.
requestAnimationFrame
Для анимаций — синхронизируется с обновлением экрана (~60 FPS):
let position = 0;
function animate() {
position += 2;
element.style.left = position + "px";
if (position < 300) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);Отмена
let animationId = requestAnimationFrame(animate);
cancelAnimationFrame(animationId);Преимущества
- Автоматическая пауза при скрытии вкладки
- Оптимальная частота обновления
- Плавная анимация
Практические примеры
Debounce
function debounce(fn, delay) {
let timerId;
return function(...args) {
clearTimeout(timerId);
timerId = setTimeout(() => fn.apply(this, args), delay);
};
}
// Использование
const search = debounce((query) => {
console.log("Поиск: " + query);
}, 300);
search("a");
search("ab");
search("abc"); // Только этот вызов выполнитсяThrottle
function throttle(fn, delay) {
let lastTime = 0;
return function(...args) {
let now = Date.now();
if (now - lastTime >= delay) {
lastTime = now;
fn.apply(this, args);
}
};
}
// Использование
const handleScroll = throttle(() => {
console.log("Скролл");
}, 100);Таймер обратного отсчёта
function countdown(seconds) {
let remaining = seconds;
let intervalId = setInterval(() => {
console.log(remaining);
remaining--;
if (remaining < 0) {
clearInterval(intervalId);
console.log("Время вышло!");
}
}, 1000);
}
countdown(5);Сравнение
| Метод | Назначение | Повторение |
|---|---|---|
setTimeout | Отложенное выполнение | Один раз |
setInterval | Регулярное выполнение | Многократно |
requestAnimationFrame | Анимация | Каждый кадр |
Практика
Задание 1: Отложенное сообщение
Задача: Выведи сообщение через 2 секунды.
Loading...
Ваш вывод:
Задание 2: Счётчик
Задача: Создай счётчик от 1 до 5 с интервалом 1 секунда.
Loading...
Ваш вывод:
Задание 3: Debounce
Задача: Реализуй простой debounce.
Loading...
Ваш вывод:
Проверь себя
- Чем
setTimeoutотличается отsetInterval? - Как отменить таймер?
- Когда использовать
requestAnimationFrame?