Методы setTimeout и setInterval. Асинхронность в JavaScript
На этом уроке мы познакомимся с таймерами, которые предназначены для вызова кода на языке JavaScript через определённые промежутки времени.
setTimeout и setInterval
В JavaScript имеются методы, которые позволяют вызвать функцию не сразу, а через некоторый промежуток времени (в асинхронном режиме). Называются они setTimeout
и setInterval
.
Отличаются они друг от друга лишь тем, что setTimeout
выполняет вызов функции всего один раз, а setInterval
– постоянно через указанный интервал времени.
Синтаксис setTimeout
и setInterval
:
// setTimeout window.setTimeout(func [, delay] [, arg1, arg2, ...]); // setInterval window.setTimeout(func [, delay] [, arg1, arg2, ...]);
Параметры:
func
– функция, которую нужно вызвать спустя указанное вdelay
количество миллисекунд;delay
– количество миллисекунд по истечении которых нужно выполнитьfunc
;arg1, arg2, ...
– дополнительные аргументы, которые нужно передать вfunc
.
Например, вызовем функцию myFunc
один раз по прошествии 3 секунд:
// функция function myFunc() { console.log('after 3 seconds'); } // вызовем функцию myFunc после 3 секунд window.setTimeout(myFunc, 3000); // выведем сообщение в консоль console.log('immediately');
При выполнение этого кода программа не остановится на месте, где мы зарегистрировали некоторую асинхронность посредством setTimeout
и не будет блокировать её дальнейшее выполнение на 3 секунды, через которые нужно будет вызвать myFunc
. Выполнение скрипта продолжится дальше и сначала браузер выведет в консоль сообщение «immediately», а затем через 3 секунды – «after 3 seconds».
Другими словами, когда браузер доходит до исполнения setTimeout
, он как бы помещает функцию myFunc
в некоторое место, а затем по прошествии определённого количества времени её вызывает. При этом блокировка основного потока выполнения программы не происходит.
Чтобы более подробно разобраться в этом необходимо рассмотреть, как движок JavaScript выполняет синхронный и асинхронный код, а также что такое event loop и как он работает.
Синхронный и асинхронный код
Но перед тем, как переходить к асинхронными операциям, следует сначала в общих чертах разобраться как выполняется синхронный код.
Выполнение такого кода движок JavaScript выполняет последовательно (т.е. строчку за строчкой). При этом перед тем, как выполнить какую-то строчку кода интерпретатор сначала помещает её в стек вызовов (call stack). Именно в нём происходит её разбор и исполнение. После этого происходит её извлечение из стека и переход к следующей строчке.
Но всё меняется, когда интерпретатор доходит до выполнения асинхронных операций, например setTimeout
. Они также как и синхронные операции сначала попадают в стек вызовов, где происходит их разбор. Но, при разборе интерпретатор понимает, что это некоторый вызов Web API и помещает эту операцию в него. После этого он удаляет эту строчку из call stack и переходит к выполнению следующей строчки кода.
В это же время Web API регистрирует эту функцию и запускает таймер. Как только он завершается, он помещает эту функцию в очередь (callback queue). Очередь – это структура данных типа FIFO. Она хранит все функции в том порядке, в котором они были туда добавлены.
Очередь обратных вызовов (callback queue) обрабатывает цикл событий (event loop). Он смотрит на эту очередь и на стек вызовов (call stack). Если стек вызовов пуст, а очередь нет – то он берёт первую функцию из очереди и закидывает её в стек вызовов, в котором она уже выполняется. Вот таким образом происходит выполнения асинхронного кода в JavaScript.
Если функцию myFunc
необходимо вызывать не один раз, а постоянно через каждые 3 секунды, то тогда вместо setTimeout
следует использовать setInterval
:
window.setInterval(myFunc, 3000);
Пример, с передачей функции аргументов:
function sayHello(name) { alert(`Привет, ${name}!`); } setTimeout(sayHello, 3000, 'Василий'); // Привет, Василий!
Пример, с использованием в setTimeout
анонимной функции:
setTimeout(function (name) { alert(`Привет, ${name}!`); }, 3000, 'Василий');
В setTimeout
и setInterval
можно также вместо функции передавать строку с кодом, который нужно выполнить через определённый интервал времени. Но этот вариант использовать не рекомендуется по тем же причинам, что и функцию eval
.
Если функция setTimeout
по каким-то причинам не работает, то проверьте действительно ли вы передаёте ссылку на функцию, а неё результат:
function sayHello() { console.log('Привет!'); } // передаём в setTimeout не ссылку на функцию sayHello, а результат её вызова setTimeout(sayHello(), 3000);
Отмена таймаута (clearTimeout)
Метод setTimeout
в результате своего вызова возвращает нам некий идентификатор таймера, который затем мы можем использовать для его отмены.
Синтаксис отмены таймаута:
const timeoutId = window.setTimeout(...); window.clearTimeout(timeoutId);
Данный метод (clearTimeout
) содержит один обязательный параметр - это уникальный идентификатор (timeoutId
) таймера, который можно получить как результат вызова метода setTimeout
.
Например:
// запустим таймер и получим его идентификатор, который будет храниться в timeoutId const timeoutId = window.setTimeout(() => { // он выведет alert с контентом 'Сообщение' через 4 секунды alert('Сообщение'); }, 4000); // остановим таймер с помощью метода clearTimeout (для этого необходимо в качестве параметра данному методу передать идентификатор таймера, хранящийся в timeoutId) clearTimeout(timeoutId);

Например, создадим на странице 2 кнопки. При нажатии на первую кнопку на экране будем отображать количество секунд, прошедших с момента её нажатия. При нажатии на вторую кнопку будем останавливать выполнение данного процесса.
Счётчик: <span id="countTime"></span> <br /> <a href="javascript:startCount()">3anycтить процесс</a> <br /> <a href="javascript:stopCount()">Остановить процесс</a> <script> // глобальная переменная, хранящая количество секунд, прошедших с момента нажатия ссылки var count=0; // глобальная переменная, хранящая идентификатор таймера var timer; //функция, выполняет следующее: //1 - выводит значения переменной count в элемент с id="clock" //2 - увеличивает значения переменной на 1 //3 - запускает таймер, который вызовет функцию timeCount() через 1 секунду function timeCount() { document.getElementById("countTime").innerHTML = count.toString(); count++; timer = window.setTimeout(function(){ timeCount() },1000); } //функция проверяет выражение !timer по правилу лжи, если оно истинно, //то вызывает функцию timeCount() function startCount() { if (!timer) timeCount(); } //функция проверяет выражение timer по правилу лжи //Если оно истинно, то она вызывает метод clearTimeOut() для прекращения работы таймера //и присваивает переменной timer значение null function stopCount() { if (timer) { clearTimeout(timer); timer=null; } } </script>

Методы setInterval и clearInterval
Метод setInterval
предназначен для вызова кода на языке JavaScript через указанные промежутки времени. Он в отличие от метода setTimeOut
будет вызвать код до тех пор, пока Вы не остановите этот таймер.
window.setInterval(Параметр_1, Параметр_2);
Метод setInterval имеет два обязательных параметра:
- 1 параметр представляет собой строку, содержащую код на языке JavaScript (например, вызов функции);
- 2 параметр задаёт интервал времени в миллисекундах, через который данный код будет вызываться.
Для прекращения работы данного таймера предназначен метод clearInterval
, которому в качестве параметра необходимо передать уникальный идентификатор (id
) таймера. Этот идентификатор можно получить при установке таймера, т.е. его возвращает метод setInterval
. Также таймер прекращает свою работу при закрытии окна.
//запустим таймер и получим его идентификатор, который будет храниться в переменной timer1 //данный таймер будет выводить сообщение через каждые 5 секунд var timer1 = window.setInterval("alert('Сообщение');",5000); //остановим работу таймера с помощью метода clearInterval(). //Для этого в качестве параметра данному методу передадим идентификатор таймера, хранящийся в переменной timer1. clearInterval(timer1);
Например, создадим цифровые часы:
<p id="clock"></p> <a href="javaScript:startClock()">3anycтить таймер</a> <br /> <a href="javaScript:stopClock()">Остановить таймер</a> <script> // глобальная переменная, хранящая идентификатор таймера var timer; //Функция для запуска таймера function startClock() { //если переменная timer содержит ложь по правилу лжи (т.е. таймер не запущен) if (!timer) { //запустить таймер, который будет вызвать функцию outClock() каждую секунду (1с = 1000мс) //идентификатор данного таймера сохраним в переменную timer (т.е. теперь переменная timer равна истине по правилу лжи). timer = window.setInterval("outClock()",1000); } } // функция для вывода даты и времени в элемент с id="clock" function outClock() { //переменная, хранящая текущую дату и время var nowDateTime = new Date(); //Выводим строку, содержащую дату и время в элемент с id="clock" document.getElementById("clock").innerHTML = nowDateTime.toLocaleTimeString(); } // функция для остановки таймера function stopClock() { //если переменная timer содержит истину по правилу лжи (т.е. таймер запущен) if(timer) { //прекращаем работу таймера window.clearInterval(timer); //присваиваем переменной timer значение null, чтобы таймер опять можно было запустить timer=null; //Выводим пустую строку в элемент с id="clock" document.getElementById("clock").innerHTML=""; } } </script>

Комментарии ()