Вы можете поинтересоваться, а зачем вообще повторно обращаться к таймеру? Что ж, единственная причина, которая приходит на ум, — для его отмены. Можно легко отменить функцию setTimeout с помощью функции clearTimeout, в которую в качестве аргумента нужно передать ID таймаута (timeoutID):
clearTimeout(timeoutID);
Если вы вообще не планируете отменять установленный таймер, можете использовать setTimeout напрямую, не прибегая к инициализации переменной.
Давайте поговорим о том, когда это применяется на практике, а именно при разработке UI (пользовательского интерфейса). При его разработке откладывание некоторых действий на определенное время достаточно распространено.
Например, когда меню разворачивается и сворачивается обратно через несколько секунд, если пользователь с ним не взаимодействует.
Или в случае, когда есть некая операция, которая выполняется слишком долго и не может завершиться, а функция setTimeout прерывает эту операцию и возвращает контроль пользователю.
Мой любимый пример (которому я также посвятил целый урок) — это использование функции setTimeout, чтобы определить, активен ли пользователь или отсутствует.
Если вы поищите информацию о setTimeout на указанном сайте или в Google, то найдете множество реальных примеров, где она может очень пригодиться.
Выполнение циклов с помощью setInterval
Следующая функция-таймер, которую мы рассмотрим, — это setInterval. Она похожа на setTimeout в том, что позволяет выполнять код спустя определенное время. Отличие же ее в том, что она не просто выполняет код один раз, а продолжает его повторное выполнение бесконечно.
Вот как она используется:
let intervalID = setInterval(someFunction, delayInMilliseconds);
За исключением имени, способ использования функции setInterval идентичен способу применения setTimeout. Первый аргумент определяет встроенный код или функцию, которую нужно выполнить. Второй аргумент определяет время задержки (интервал) между выполнениями. При желании вы также можете инициализировать функцию setInterval как переменную для хранения ID интервала, который позднее сможете использовать, например, для прекращения выполнения.
Отлично! Теперь, когда вы уже знакомы с процессом, рассмотрите пример кода, выполняющего функцию drawText с интервалом между циклами в 2 секунды:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Show me some text!</title>
</head>
<body>
<script>
let thingToPrint = "";
function drawText() {
thingToPrint += "#";
document.writeln(thingToPrint);
}
setInterval(drawText, 2000);
</script>
</body>
</html>
Для прекращения выполнения цикла мы можем использовать функцию clearInterval с соответствующим аргументом:
clearInterval(intervalID);
Используется она в точности как clearTimeout — мы передаем ей ID таймера setInterval, который при желании можем задать в момент его создания.
В реальной жизни функция setInterval долгое время оставалась основной функцией для создания анимации в JavaScript. Например, если потребуется получить 30 или 60 кадров в секунду, вы будете «играть» со значением задержки времени примерно так:
// 1000 разделить на 60 — это значение в миллисекундах для 60fps
setInterval(moveCircles, 1000 / 60);
Чтобы увидеть работу setInterval и в других реалистичных примерах на самом сайте, загляните в конец статьи «Создание симпатичного слайдера контента» (https://www.kirupa.com/html5/creating_a_sweet_content_slider.htm) или прочтите материал «Создание аналоговых часов» (https://www.kirupa.com/html5/create_an_analog_clock_using_the_canvas.htm). И там и там вы найдете достаточно яркие примеры использования setInterval.
Плавная анимация с помощью requestAnimationFrame
Настало время перейти к моей любимой функции: requestAnimatonFrame. Эта функция создана для синхронизации кода с событием перерисовки содержимого браузера. Поясняю подробнее: в любой момент браузер занят обработкой миллиона различных элементов. Среди них: манипуляции с макетом, реакция на прокрутку страниц, прослушивание кликов мыши, отображение результатов нажатий клавиатуры, исполнение кода, загрузки ресурсов и т. д. Одновременно со всем этим он также перерисовывает экран со скоростью 60 кадров в секунду, ну или пытается это делать.
Если у вас есть код, запускающий какую-либо анимацию на экране, скорее всего, вам захочется, чтобы эта анимация выполнялась корректно и не затерялась в остальной мешанине действий, выполняемых браузером. В таких случаях использование ранее отмеченной техники setInterval не гарантирует, что скорость обновления не упадет, когда браузер будет занят оптимизацией других элементов. Чтобы браузер не приравнивал код, отвечающий за анимацию, любому другому JavaScript-коду, существует функция requestAnimationFrame. Браузеры воспринимают эту функцию особым образом, что позволяет задавать время ее выполнения наиболее оптимально, избегая провала частоты кадров, а также ненужных действий и прочих побочных эффектов, мешающих применению других решений, связанных с выполнением циклов.