Метод setTimeout — это встроенная функция JavaScript, устанавливающая таймер обратного отсчета (в миллисекундах) для выполнения функции обратного вызова по завершении заданного времени.
Представьте, что у вас появилась задача сделать всплывающее окно с приветствием, отображаемое через две секунды после того, как пользователь зашел на сайт. Или же необходимо воспроизвести звук через секунду после объявления победителя в онлайн-игре. В такой ситуации вам не нужно, чтобы функция запускалась немедленно. Надо отложить ее выполнение или запустить через определенный интервал времени.
Как реализовать такую задумку? Именно для решения подобных задач в JavaScript существуют два метода объекта window: setTimeout
и setInterval
. В этой статье мы рассмотрим их грамотное использование и практическую реализацию.
Метод setTimeout
запускается только один раз за вызов, а значит после завершения выполнения функции setTimeout
прекращает свою работу.
Основной и наиболее часто используемый синтаксис этой функции:
setTimeout (функция обратного вызова, задержка в миллисекундах)
В этом примере все просто: функция обратного вызова сработает по завершении временной задержки. Давайте рассмотрим пример, как использовать эту функцию на практике:
function greet () { alert ('Welcome!'); } setTimeout (greet, 2000) ; // приветствие появится через 2000 миллисекунд (2 секунды)
setTimeout ()
позволяет нам назначить столько аргументов, сколько необходимо для функции обратного вызова. Предположим, что мы хотим поприветствовать Джона — пользователя, вошедшего в нашу систему. Для этого нам необходимо просто добавить аргументы в конец списка параметров setTimeout
:
setTimeout (функция обратного вызова, задержка в миллисекундах, arg1)
Посмотрим, как это реализовать:
const loggedInUser = 'Джон' ; function greet (userName) { alert ('Добро пожаловать' + userName + '!'); } setTimeout (greet, 2000, loggedInUser);
В приведенном примере в появившемся через две секунды всплывающем окне будет написано «Добро пожаловать, Джон!». Здесь мы взяли имя пользователя из переменной loggedInUser
и добавили его в функцию обратного вызова в качестве параметра.
Важно: не передавайте аргументы функции обратного вызова напрямую и не ставьте скобки после имени функции внутри метода setTimeout
, если аргументов нет!
Глядя на код предыдущего примера у вас может возникнуть соблазн передать аргументы в качестве параметров функции обратного вызова. Например:
SetTimeout (Greet(loggedInUser), 2000);
или
SetTimeout (Greet(),2000) ;
Это логическая ошибка. В приведенной выше строке кода функция обратного вызова выполняется немедленно, а параметр задержки уже не воспринимается интерпретатором. Получается, что мы не передаем объект функции в качестве метода обратного вызова в setTimeout ()
, а скорее устанавливаем возвращаемое значение функции. В такой ситуации таймер будет проигнорирован.
Чтобы исправить эту ошибку, просто измените шаблон вызова, удалите скобки после имени функции, добавив аргументы (если они есть) в конец списка параметров setTimeout ()
.
Наши друзья из Mate Academy помогут всем заинтересованным разобраться в особенностях работы с setTimeout и setInterval. Запишитесь на специальный курс и получите ценные знания.
Иногда бывают ситуации, когда нам нужно отменить начавшуюся временную задержку. Что делать в этом случае? Метод setTimeout ()
возвращает ключ, позволяющий ссылаться на выполнение callback-функции. Мы можем использовать этот ключ как кнопку прерывания, тем самым взяв в свои руки контроль над самим механизмом тайм-аута. Например:
const timerId = setTimeout(Greet, 5000, loggedInUser);
Здесь timerId
— тот самый ключ, используемый для ссылки на текущий таймер. Чтобы отменить тайм-аут, этот ключ нужно передать функции clearTimeout ()
в качестве параметра:
function _clear_ () { clearTimeout (timerId); }
При использовании clearTimeout()
происходит отмена таймера, и функция обратного вызова внутри метода не сработает.
Метод setInterval
используется для повторного выполнения функции по истечении определенного периода времени. Схема построения этого метода следующая:
const timerID = setInterval(function, delay, arg1, arg2, ...)
В этом случае задержка — это время в миллисекундах, в течение которого таймер должен задерживать последовательные выполнения функции.
Синтаксис этого метода очень похож на синтаксис setTimeout
, но в отличие от последнего, setInterval
запускает функцию несколько раз, пока она не будет отменена. Например:
function sayHello(name) { console.log(`Hello, ${name}`) } setInterval(sayHello, 3000, "John")
В примере метод будет повторно выводить в консоль Hello John каждые три секунды.
Чтобы остановить непрерывный вызов функции setInterval
, используется метод clearInterval()
. Он принимает идентификатор таймера в качестве аргумента и использует этот идентификатор для остановки таймера.
Вернемся к нашему примеру:
let counter = 0; function sayHello(name) { alert(`Hello, ${name}`) counter++; if (counter === 3) { clearInterval(timerID) } } let timerID = setInterval(sayHello, 3000, "John");
Функция sayHello
будет выполнена всего три раза.
Вы можете задаться вопросом, почему оператор if
находится внутри функции, а не за ее пределами, вот так:
let counter = 0; function sayHello(name) { alert(`Hello, ${name}`) counter++; } let timerID = setInterval(sayHello, 3000, "John") if (counter === 3) { clearInterval(timerID) }
Для того чтобы ответить на него, необходимо разобраться, как JavaScript выполняет рассматриваемые нами методы. В отличие от других языков, в JS — один поток для решения задач, выполняемый построчно. Это значит, что каждая строка кода должна завершить свое выполнение, прежде чем переходить к следующей. Другими словами, выполнение остального кода блокируется.
Но есть операции ввода-вывода, которые не блокируются. Они обрабатываются базовым механизмом. К ним относятся:
setTimeout
;setInterval
. Поэтому JavaScript не ждет, пока функция обратного вызова, переданная методу setTimeout
или setInterval
, завершит выполнение прежде, чем перейти к следующей задаче или строке кода.
Следовательно, если бы мы прописали реализацию метода вторым способом, таймер не перестал бы работать, ведь после выполнения строки let timerID = setInterval(sayHello, 3000, "John")
JavaScript перешел бы к следующему блоку кода if (counter === 3) {clearInterval(timerID)}
и условие не выполнилось бы.
Метод setInterval
запускает функцию каждые n миллисекунд, не обращая внимания на то, когда она завершится.
Если функция каждый раз срабатывает с одним и тем же временным интервалом, тогда все в порядке:
Но бывают случаи, когда время выполнения меняется в зависимости от условий сети, например:
Или перекрывает следующее:
Чтобы избежать последствий подобных случаев, вы можете запланировать рекурсивный вызов setTimeout
по завершении функции обратного вызова.
Для наглядности рассмотрим распространенный пример сервиса по отправке запросов на сервер, который при перегрузке последнего увеличивал бы интервал следующего запроса:
let delay = 5000; let timerId = setTimeout(function request() { ...функционал для отправки запроса... if ( сервер перегружен ) { // увеличиваем интервал последующего запроса delay *= 2; } timerId = setTimeout(request, delay); }, delay);
C рекурсивным setTimeout
мы можем изменять последующий вызов, исходя из результата предыдущего.
Схема здесь такая:
Другими словами, такой подход дает фиксированную временную задержку, ведь новый вызов планируется, когда закончился вызов перед ним.
На функцию из рассматриваемых методов создается внутренняя ссылка и прописывается в планировщик. Сохранившись там, она не попадет в Garbage Collector даже в том случае, когда на нее ничто не ссылается. Функцию же setInterval
сотрет из памяти только метод clearInterval
.
Но здесь есть свои подводные камни. Функция обратного вызова все равно будет взаимодействовать с внешними переменными, иногда занимающими больше памяти, чем она сама. В таком случае при отсутствии большой необходимости в частом вызове функции есть смысл его отменить.
В официальной документации к setTimeout
написано, что delay (временная задержка) — необязательное поле. Если оно не указано, то таймер равен нулю и функция обратного вызова срабатывает «мгновенно или как можно скорее». Такая странная формулировка обусловлена наличием у браузера своего таймера с минимально возможной задержкой. Она может варьироваться от 4 мс в современных браузерах, до 15 мс в более старых. Но срабатывать она может и реже — с опозданием вплоть до 1000 мс.
Это связано с особенностью некоторых браузеров запускать таймер на неактивной странице. Этим грешат Google Chrome, Firefox, IE10. На частоту запуска функции также влияют загрузка процессора и режим экономии энергии разряженной батареи при работе на ноутбуке. Узнать более подробно об остальных особенностях работы, можно записавшись на онлайн курс к нашим друзьям Mate Academy.
Рассмотрим простой пример реализации всплывающего сообщения, появляющегося спустя 2000 миллисекунд после наведения мышкой на элемент. Условие: если курсор убрали раньше, сообщение не нужно показывать.
var timerId; element.hoverover = function() { timerId = setTimeout(function() { alert(1); }, 2000); }; element.hoverout = function() {clearTimeout(timerId);};
Примечание: если методу clearTimeout
передан неправильный идентификатор, то изменений не произойдет. Поэтому здесь можно не проверять работу таймера и содержимое timerId
.
setInterval
и setTimeout
нужны для отложенного запуска необходимого нам функционала.setTimeout
сразу прекращает свою работу при запуске отложенной функции, а остановить его во время выполнения, может метод clearTimeout
.setInterval
заставляет callback-функцию выполняться с заданным интервалом. Для его остановки в JS предусмотрен метод clearInterval()
.setTimeout
, гарантирующий фиксированную временную задержку между вызовами функции.setTimeout
задержка вызова функции зависит от браузерного таймера, загруженности центрального процессора и режима расходования энергии при работе на ноутбуке.
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…