SetTimeout: примеры (JAVASCRIPT)
setTimeout(callback (function), delay (number), ...args (any)): numberФункция setTimeout
Функция setTimeout является частью Web API и позволяет отложить выполнение кода на указанное количество миллисекунд. Она часто используется для создания задержек, анимаций, троттлинга и дебаунсинга событий.
Когда используется:
- Отложенный запуск функции.
- Создание анимаций и интерактивных элементов.
- Ограничение частоты вызова обработчиков событий (дебаунсинг и троттлинг).
- Имитация асинхронного поведения.
- Установка таймаутов для операций.
Аргументы:
callback(функция или строка кода) — функция, которую нужно выполнить после задержки. Использование строки кода (например,"alert('Hi')") не рекомендуется из-за проблем с безопасностью и производительностью.delay(число, необязательный) — задержка в миллисекундах перед выполнением. По умолчанию 0. Реальная задержка может быть больше из-за Single-threaded nature Event Loop.arg1, arg2, ...(необязательные) — дополнительные аргументы, которые будут переданы в функцию обратного вызова.
Возвращаемое значение:
Функция возвращает числовой timeoutID — уникальный идентификатор таймера. Этот идентификатор можно использовать для отмены выполнения с помощью функции clearTimeout(timeoutID).
Основные примеры
Пример 1: Базовое использование
console.log('Начало');
setTimeout(() => {
console.log('Сообщение после задержки');
}, 2000);
console.log('Конец');Начало Конек Сообщение после задержки (через 2 секунды)
Пример 2: Передача аргументов в колбэк
function greet(name, punctuation) {
console.log(`Привет, ${name}${punctuation}`);
}
setTimeout(greet, 1000, 'Анна', '!');Привет, Анна! (через 1 секунду)
Пример 3: Отмена выполнения
const timeoutId = setTimeout(() => {
console.log('Это сообщение не появится');
}, 3000);
clearTimeout(timeoutId);
console.log('Таймер отменен');Таймер отменен
Похожие функции в JavaScript
Функция setInterval вызывает переданную функцию неоднократно с заданным интервалом. Возвращает intervalID. Останавливается с помощью clearInterval.
let counter = 0;
const intervalId = setInterval(() => {
console.log(`Тик ${++counter}`);
if (counter >= 5) clearInterval(intervalId);
}, 1000);Тик 1 (через 1 сек) Тик 2 (через 2 сек) ... Тик 5 (через 5 сек)
requestAnimationFrame
Оптимизированный метод для анимаций, синхронизированный с частотой обновления экрана. Предпочтительнее setTimeout для плавной анимации.
let start = Date.now();
function animate() {
let timePassed = Date.now() - start;
console.log(`Прошло времени: ${timePassed}мс`);
if (timePassed < 2000) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);Выбор функции зависит от задачи: setTimeout для разовых задержек, setInterval для повторяющихся действий, requestAnimationFrame для анимаций.
Аналоги в других языках программирования
Python (time.sleep, threading.Timer)
В Python для паузы используется time.sleep, но он блокирует весь поток. Для асинхронного выполнения можно использовать threading.Timer или асинхронные конструкции asyncio.sleep.
import time
print("Начало")
time.sleep(2)
print("После задержки")
# Или асинхронно с asyncio:
# import asyncio
# async def main():
# print("Начало")
# await asyncio.sleep(2)
# print("После задержки")
# asyncio.run(main())Начало (пауза 2 секунды) После задержки
PHP (sleep, usleep)
Функции sleep (секунды) и usleep (микросекунды) также блокируют выполнение скрипта.
<?php
echo "Начало";
sleep(2); // Задержка в секундах
echo "После задержки";
?>Начало (пауза 2 секунды) После задержки
C/C++ (Sleep)
В Windows API используется функция Sleep из windows.h (задержка в миллисекундах). В стандарте C++11 и выше можно использовать std::this_thread::sleep_for.
#include <iostream>
#include <chrono>
#include <thread>
int main() {
std::cout << "Начало";
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "После задержки";
return 0;
}В отличие от JavaScript, большинство аналогов являются синхронными и блокирующими.
Распространенные ошибки
Ошибка 1: Неправильный контекст `this`
При передаче метода объекта в setTimeout теряется контекст `this`.
const obj = {
name: 'Объект',
logName() {
console.log(this.name);
}
};
setTimeout(obj.logName, 100); // Выведет undefined
// Решение: использовать стрелочную функцию или bind
setTimeout(() => obj.logName(), 200);
setTimeout(obj.logName.bind(obj), 300);undefined Объект (через 200 мс) Объект (через 300 мс)
Ошибка 2: Замыкание в цикле
Классическая проблема: все таймеры в цикле используют одно и то же значение переменной на момент выполнения.
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), i * 1000);
}
// Все выведут 4 (если var) или 3 (если let без замыкания)4 4 4
Решение — создать новую область видимости для каждой итерации (использовать `let` с дополнительной функцией или IIFE).
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), i * 1000);
}1 2 3
Ошибка 3: Ожидание точной задержки
setTimeout гарантирует минимальную, но не точную задержку из-за занятости основного потока.
const start = Date.now();
setTimeout(() => {
console.log(`Прошло: ${Date.now() - start} мс`);
}, 100);
// Длительная операция блокирует Event Loop
for (let i = 0; i < 1e8; i++) {}Прошло: 550 мс (значительно больше 100 мс)
Изменения в последних версиях
Спецификация функции setTimeout остается стабильной в рамках ECMAScript, так как она является частью Web API, а не ядра языка. Однако, среда выполнения (браузеры, Node.js) могут вносить изменения.
- В современных браузерах минимальная задержка для вложенных таймеров (после 5 уровней вложенности) увеличивается до 4 мс (как указано в стандарте HTML5).
- В неактивных вкладках браузеры могут замедлять выполнение
setTimeoutдо 1 раза в секунду для оптимизации ресурсов. - Node.js имеет свои аналоги (
setTimeoutиз модуляtimers) с дополнительными возможностями, такими какref()иunref(). - Появились новые API, такие как
queueMicrotaskиscheduler.postTask, которые предлагают более точный контроль над очередями задач.
Расширенные примеры использования
Пример 1: Дебаунсинг (устранение дребезга)
Техника для ограничения частоты вызова функции, например, при обработке событий прокрутки или ввода.
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
const handleInput = debounce((value) => {
console.log(`Отправка запроса с: ${value}`);
}, 500);
// Имитация быстрого ввода
handleInput('A');
handleInput('AB');
handleInput('ABC'); // Только этот вызов сработает через 500 мсОтправка запроса с: ABC (через 500 мс после последнего вызова)
Пример 2: Троттлинг (ограничение частоты)
Гарантирует, что функция выполняется не чаще, чем раз в указанный период.
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
const logScroll = throttle(() => console.log('Прокрутка!'), 1000);
// Многократный вызов в течение секунды сработает только один раз
logScroll(); // Сработает
logScroll(); // Проигнорировано
logScroll(); // Проигнорировано
// Через 1 секунду снова можно будет вызватьПрокрутка! (остальные вызовы в течение секунды игнорируются)
Пример 3: Создание цепочки таймеров (аналог последовательных задержек)
Позволяет выполнять код с паузами между этапами.
function sequentialTimer(...actions) {
let totalDelay = 0;
actions.forEach(([callback, delay]) => {
totalDelay += delay;
setTimeout(callback, totalDelay);
});
}
sequentialTimer(
[() => console.log('Шаг 1'), 1000],
[() => console.log('Шаг 2'), 2000],
[() => console.log('Шаг 3'), 500]
);Шаг 1 (через 1 сек) Шаг 2 (через 3 сек от начала) Шаг 3 (через 3.5 сек от начала)
Пример 4: Использование с промисами
Оборачивание setTimeout в промис для использования в асинхронном коде.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function delayedGreeting() {
console.log('Ждем...');
await delay(2000);
console.log('Привет!');
}
delayedGreeting();Ждем... Привет! (через 2 секунды)
Пример 5: Измерение времени выполнения с таймаутом
Установка ограничения по времени для выполнения операции.
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Таймаут')), ms)
);
return Promise.race([promise, timeout]);
}
const slowOperation = new Promise(resolve => setTimeout(() => resolve('Данные'), 3000));
withTimeout(slowOperation, 2000)
.then(data => console.log(data))
.catch(err => console.log(err.message)); // Сработает таймаутТаймаут (через 2 секунды, хотя операция занимает 3)