Как правильно вывести приветствие через 5 секунд после запуска скрипта

от admin

Планирование: setTimeout и setInterval

Мы можем вызвать функцию не в данный момент, а позже, через заданный интервал времени. Это называется «планирование вызова».

Для этого существуют два метода:

  • setTimeout позволяет вызвать функцию один раз через определённый интервал времени.
  • setInterval позволяет вызывать функцию регулярно, повторяя вызов через определённый интервал времени.

Эти методы не являются частью спецификации JavaScript. Но большинство сред выполнения JS-кода имеют внутренний планировщик и предоставляют доступ к этим методам. В частности, они поддерживаются во всех браузерах и Node.js.

setTimeout

func|code Функция или строка кода для выполнения. Обычно это функция. По историческим причинам можно передать и строку кода, но это не рекомендуется. delay Задержка перед запуском в миллисекундах (1000 мс = 1 с). Значение по умолчанию – 0. arg1 , arg2 … Аргументы, передаваемые в функцию

Например, данный код вызывает sayHi() спустя одну секунду:

Если первый аргумент является строкой, то JavaScript создаст из неё функцию.

Это также будет работать:

Но использование строк не рекомендуется. Вместо этого используйте функции. Например, так:

Начинающие разработчики иногда ошибаются, добавляя скобки () после функции:

Это не работает, потому что setTimeout ожидает ссылку на функцию. Здесь sayHi() запускает выполнение функции, и результат выполнения отправляется в setTimeout . В нашем случае результатом выполнения sayHi() является undefined (так как функция ничего не возвращает), поэтому ничего не планируется.

Отмена через clearTimeout

Вызов setTimeout возвращает «идентификатор таймера» timerId , который можно использовать для отмены дальнейшего выполнения.

Синтаксис для отмены:

В коде ниже планируем вызов функции и затем отменяем его (просто передумали). В результате ничего не происходит:

Как мы видим из вывода alert , в браузере идентификатором таймера является число. В других средах это может быть что-то ещё. Например, Node.js возвращает объект таймера с дополнительными методами.

Повторюсь, что нет единой спецификации на эти методы, поэтому такое поведение является нормальным.

Для браузеров таймеры описаны в разделе таймеров стандарта HTML5.

setInterval

Метод setInterval имеет такой же синтаксис как setTimeout :

Все аргументы имеют такое же значение. Но отличие этого метода от setTimeout в том, что функция запускается не один раз, а периодически через указанный интервал времени.

Чтобы остановить дальнейшее выполнение функции, необходимо вызвать clearInterval(timerId) .

Следующий пример выводит сообщение каждые 2 секунды. Через 5 секунд вывод прекращается:

В большинстве браузеров, включая Chrome и Firefox, внутренний счётчик продолжает тикать во время показа alert/confirm/prompt .

Так что если вы запустите код выше и подождёте с закрытием alert несколько секунд, то следующий alert будет показан сразу, как только вы закроете предыдущий. Интервал времени между сообщениями alert будет короче, чем 2 секунды.

Вложенный setTimeout

Есть два способа запускать что-то регулярно.

Один из них setInterval . Другим является вложенный setTimeout . Например:

Метод setTimeout выше планирует следующий вызов прямо после окончания текущего (*) .

Вложенный setTimeout – более гибкий метод, чем setInterval . С его помощью последующий вызов может быть задан по-разному в зависимости от результатов предыдущего.

Например, необходимо написать сервис, который отправляет запрос для получения данных на сервер каждые 5 секунд, но если сервер перегружен, то необходимо увеличить интервал запросов до 10, 20, 40 секунд… Вот псевдокод:

А если функции, которые мы планируем, ресурсоёмкие и требуют времени, то мы можем измерить время, затраченное на выполнение, и спланировать следующий вызов раньше или позже.

Вложенный setTimeout позволяет задать задержку между выполнениями более точно, чем setInterval .

Сравним два фрагмента кода. Первый использует setInterval :

Второй использует вложенный setTimeout :

Для setInterval внутренний планировщик будет выполнять func(i) каждые 100 мс:

Реальная задержка между вызовами func с помощью setInterval меньше, чем указано в коде!

Это нормально, потому что время, затраченное на выполнение func , использует часть заданного интервала времени.

Вполне возможно, что выполнение func будет дольше, чем мы ожидали, и займёт более 100 мс.

В данном случае движок ждёт окончания выполнения func и затем проверяет планировщик и, если время истекло, немедленно запускает его снова.

В крайнем случае, если функция всегда выполняется дольше, чем задержка delay , то вызовы будут выполняться без задержек вообще.

Ниже представлено изображение, показывающее процесс работы рекурсивного setTimeout :

Вложенный setTimeout гарантирует фиксированную задержку (здесь 100 мс).

Это потому, что новый вызов планируется в конце предыдущего.

Когда функция передаётся в setInterval/setTimeout , на неё создаётся внутренняя ссылка и сохраняется в планировщике. Это предотвращает попадание функции в сборщик мусора, даже если на неё нет других ссылок.

Для setInterval функция остаётся в памяти до тех пор, пока не будет вызван clearInterval .

Есть и побочный эффект. Функция ссылается на внешнее лексическое окружение, поэтому пока она существует, внешние переменные существуют тоже. Они могут занимать больше памяти, чем сама функция. Поэтому, если регулярный вызов функции больше не нужен, то лучше отменить его, даже если функция очень маленькая.

setTimeout с нулевой задержкой

Особый вариант использования: setTimeout(func, 0) или просто setTimeout(func) .

Это планирует вызов func настолько быстро, насколько это возможно. Но планировщик будет вызывать функцию только после завершения выполнения текущего кода.

Так вызов функции будет запланирован сразу после выполнения текущего кода.

Например, этот код выводит «Привет» и затем сразу «Мир»:

Первая строка помещает вызов в «календарь» через 0 мс. Но планировщик проверит «календарь» только после того, как текущий код завершится. Поэтому "Привет" выводится первым, а "Мир" – после него.

Есть и более продвинутые случаи использования нулевой задержки в браузерах, которые мы рассмотрим в главе Событийный цикл: микрозадачи и макрозадачи.

В браузере есть ограничение на то, как часто внутренние счётчики могут выполняться. В стандарте HTML5 говорится: «после пяти вложенных таймеров интервал должен составлять не менее четырёх миллисекунд.».

Продемонстрируем в примере ниже, что это означает. Вызов setTimeout повторно вызывает себя через 0 мс. Каждый вызов запоминает реальное время от предыдущего вызова в массиве times . Какова реальная задержка? Посмотрим:

Первый таймер запускается сразу (как и указано в спецификации), а затем задержка вступает в игру, и мы видим 9, 15, 20, 24. .

Аналогичное происходит при использовании setInterval вместо setTimeout : setInterval(f) запускает f несколько раз с нулевой задержкой, а затем с задержкой 4+ мс.

Это ограничение существует давно, многие скрипты полагаются на него, поэтому оно сохраняется по историческим причинам.

Этого ограничения нет в серверном JavaScript. Там есть и другие способы планирования асинхронных задач. Например, setImmediate для Node.js. Так что это ограничение относится только к браузерам.

Итого

  • Методы setInterval(func, delay, . args) и setTimeout(func, delay, . args) позволяют выполнять func регулярно или только один раз после задержки delay , заданной в мс.
  • Для отмены выполнения необходимо вызвать clearInterval/clearTimeout со значением, которое возвращают методы setInterval/setTimeout .
  • Вложенный вызов setTimeout является более гибкой альтернативой setInterval . Также он позволяет более точно задать интервал между выполнениями.
  • Планирование с нулевой задержкой setTimeout(func,0) или, что то же самое, setTimeout(func) используется для вызовов, которые должны быть исполнены как можно скорее, после завершения исполнения текущего кода.
  • Браузер ограничивает 4-мя мс минимальную задержку между пятью и более вложенными вызовами setTimeout , а также для setInterval , начиная с 5-го вызова.

Обратим внимание, что все методы планирования не гарантируют точную задержку.

Например, таймер в браузере может замедляться по многим причинам:

  • Перегружен процессор.
  • Вкладка браузера в фоновом режиме.
  • Работа ноутбука от аккумулятора.

Всё это может увеличивать минимальный интервал срабатывания таймера (и минимальную задержку) до 300 или даже 1000 мс в зависимости от браузера и настроек производительности ОС.

Задачи

Вывод каждую секунду

Напишите функцию printNumbers(from, to) , которая выводит число каждую секунду, начиная от from и заканчивая to .

Show JS Alert after 5 seconds

I am trying to show a JS alert after 5 seconds. Right now I have this code:

The problem is that it’s not working right. There is some kind of little error I can’t see in the code.

6 Answers 6

Why are you using setInterval and maintaining a count variable to deduce when five seconds have passed?

Your code could be simplified using setTimeout. For example:

Your code is working fine .Check this JSFIDDLE

Show JS Alert after 5 seconds

where as you are using setInterval which mean the timer function will execute in every 1 second and it will keep on executing even after alerting. Check console from developer’s tool

Not sure if you need setInterval or if you are actually looking for setTimeout

Понимание таймеров в JavaScript. Callback-функции, setTimeout, setInterval и requestAnimationFrame

В предыдущей статье Путешествие по JavaScript таймерам в сети от Нолана Лоусона многие в сети и в офлайне высказали недопонимание того, о чём там пишется, но тема всем показалась очень интересной и занимательной. Поэтому я решил исправиться и продолжить тему более детально, собрав хороший материал по каждому таймеру, где объясняется конкретно то, как он работает.

В статье присутствует адаптированный и дополненный материал с переводами статей:

��Мой Твиттер — там много из мира фронтенда, да и вообще поговорим��. Подписывайтесь, будет интересно: ) ✈️

Что такое callback-функции?

Или просто колбэки. Прежде, чем вообще начинать понимать таймеры и асинхронность, нужно разобраться с callback функциями. Что же это такое?

Простое определение: колбэк это функция, которая выполнится после другой функции, завершившей своё выполнение. Следовательно, отсюда и название, ‘call back’.

Определение посложнее: В JavaScript, функции это объекты. Поэтому, функции, могут брать другие функции в виде аргументов и также могут быть возвращены другими функциями. Функции которые так делают, называются функциями высшего порядка. Любая функция, которая передается как аргумент — именуется callback-функцией.

Что-то много слов. Давайте посмотрим на примерах и разберемся поглубже.

Зачем нам вообще колбэки?

По одной простой и важной причине — JavaScript это событийно-ориентированный язык. Это говорит нам о том, что вместо ожидания ответа для последующего шага, JavaScript продолжит выполнение, следя за другими событиями (ну или ивентам, кому как удобнее). Давайте взглянем на простой пример:

Как вы и ожидали, функция first выполнится первой, а функция second выполнится второй — все это выдаст в консоль следующее:

Но что, если функция first будет содержать код, который не может быть немедленно выполнен. Для примера, API запрос, где нам нужно отправить информацию, а затем подождать ответ? Чтобы симулировать такое действие, мы применим setTimeout (дальше будет подробнее про него), который является функцией JavaScript, вызывающей другую функцию после определенного количества времени. То есть, мы задержим нашу функцию на 500 миллисекунд, чтобы симулировать API запрос. Таким образом, наш новый код будет выглядеть так:

Пока что совершенно неважно, понимаете ли вы то, как работает setTimeout() . Всё, что важно — это то, чтобы вы увидели, что мы отсрочили console.log(1) на 500 миллисекунд. И так, что случится, когда мы вызовем наши функции?

Пусть даже мы и вызываем first() первой, мы выводим в лог результат этой функции, после функции second() .

Не то чтобы JavaScript не выполняет наши функции в том порядке, в котором нам надо, просто вместо этого, JavaScript не ждал ответа от first() перед тем, чтобы идти дальше, для выполнения second() .

Так зачем вам это? А затем, что вы не можете просто вызывать одну функцию за другой и надеяться, что они выполнятся в правильном порядке. Колбэки это способ убедиться в том, что конкретный код не выполняется перед другим отрезком кода, который ещё не закончил своё выполнение.

Создаём callback

Достаточно разговоров, давайте создадим callback!

Во-первых, откройте Chrome Developer Console (Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J) и введите следующий код функции:

Итак, выше мы создали функцию doHomework . Наша функция берёт одну переменную, это subject . Вызовите функцию, введя следующее в вашу консоль:

Теперь давайте добавим callback — как последний параметр в функции doHomework() , мы можем передать callback. Callback-функция теперь является вторым аргументом вызова doHomework() .

Как вы видите, введя код выше в вашу консоль, вы получите один за другим два оповещения. Первое starting homework и второе, которое последует за ним finished homework.

Но колбэкам необязательно всегда быть определенными в вызове функции. Они могут быть определены где угодно в коде. Например как тут:

Результат этого примера точно такой же, как и результат предыдущего, но настройка идёт немного по-другому. Как вы видите, мы передали функцию alertFinished как аргумент, во время вызова функции doHomework() .

Пример из реального мира

На прошлой неделе я опубликовал статью о том, как создать бота в Twitter в 38 строчек кода. Единственной причиной, по которой код в этой статье работал, был API от Twitter. Когда вы делаете запросы по API, вам нужно подождать ответа, перед тем как вы сможете как-то с ним работать и соответственно на него воздействовать. Вот то, как выглядит сам запрос.

T.get просто означает то, что мы делаем get запрос к Twitter.

У этого запроса есть три параметра: ‘search/tweets’ , которые служит маршрутом для нашего запроса, params которые являются параметрами поиска и дальше идёт анонимная функция, которая и является колбэком.

Колбэк тут крайне важен, так как нам нужно подождать ответа сервера, перед тем как идти дальше в выполнении кода. Мы понятия не имеем, будет ли наш API запрос успешным или нет, так что после отправки наших параметров к search/tweets через запрос get — мы ждём. Как только Twitter ответит, вызовется наша callback-функция. Twitter либо отправит err объект (т.е. ошибку) или объект response . В нашем колбэке мы можем применить if() , чтобы определить был ли наш запрос проведен успешно или нет, а за тем уже соответственно работать с новыми данными.

В этой теме можно было бы ещё коснуться рекурсий, но это немного другая песня, которая требует более детального понимания.

Таймеры setTimeout и setInterval

Каждый блок JavaScript кода, как правило, выполняется синхронно. Но в коробке у JavaScript уже есть нативные функции (таймеры), которые позволяют задерживать выполнение какого-либо кода.

Это setTimeout() и setInterval() . Они позволят вам запустить кусок JavaScript кода в определенный момент в будущем. Такой подход называется “отложенным вызовом”. Далее вы узнаете как работают эти два метода и увидите несколько практических примеров.

setTimeout()

Эту функцию вы видели выше, а сейчас узнаете про неё ещё детальнее. Она используется в основном в тех случаях, если вы хотите запустить вашу функцию через конкретное количество миллисекунд после вызова самого setTimeout() . Синтаксис для этого метода такой:

Тут expression в JavaScript коде запустится по прошествии миллисекунд, указанных в аргументе timeout .

setTimeout() также возвращает ID для тайм-аута, чтобы его можно было отследить. Но в основном оно используется для метода clearTimeout() , который останавливает выполнение отложенной функции. В качестве аргумента тут нужно вставить ID (название) функции.

Вот ещё один пример:

При нажатии на кнопку запускается setTimeout() метод. Выражение, запуск которого по вашему предусмотрению должен произойти с задержкой в 4000ms или 4 секунды, уже передано.

Тут стоит обратить внимание на то, что setTimeout() не останавливает выполнение дальнейшего скрипта во время периода тайм-аута. Он просто откладывает выполнение указанного блока кода на заложенное количество времени. После вызова функции setTimeout() , скрипт продолжит выполняться обычным образом, с таймером на фоне.

То, что выше — это простой пример со всем кодом для alert бокса в setTimeout вызове. На практике же, вы будете вызывать функции внутри таймеров гораздо чаще. Следующий пример даст вам лучшее понимание о вызове функций с помощью setTimeout() .

Читать:
Почему не работают горячие клавиши

Для примера, код ниже, вызывает sayHello() через одну секунду:

Вы можете также передавать аргументы вместе с функцией, например, как тут:

Как вы видите, для setTimeout() сначала передаётся функция аргумент, затем время задержки и уже только потом аргументы для функции аргумента(пардон за каламбур).

Если первый аргумент это строка, то JavaScript может создать из неё функцию. Так что вот это тоже сработает:

Но применение такого метода не рекомендуется, лучше используйте функции, как тут:

setInterval()

Эта функция, как и предполагается из названия, в основном используется для задержки функций, которые будут выполняться снова и снова, например анимации. Функция setInterval() очень близка к setTimeout() , у них даже такой же синтаксис:

Но разница тут вот в чём. setTimeout() запускает expression только единожды, в то время, как setInterval() продолжает запускать expression на регулярной основе после заданного временного интервала, пока вы не скажете стоп.

Для того, чтобы остановить последующие вызовы в setInterval() , вам нужно вызывать clearInterval(timerId) , где timerId это имя функции setInterval .

Когда вам нужно использовать setInterval() ? Когда вам не нужно вызывать setTimeout() в конце спланированной функции. Также, во время использования setInterval() , фактически не существует задержки между одним срабатыванием настоящего выражения и последующим. А в setTimeout() существует относительно долгая задержка, во время выполнения выражения, вызова функции и выставления нового setTimeout . Так что если вам нужен обычный точный таймер и надо, чтобы что-то делалось повторно после определенного временного интервала, тогда setInterval это ваш выбор.
Итак, сейчас мы подобрались к самому интересному. А именно к requestAnimationFrame . А про него нужно рассказать максимально подробно.

requestAnimationFrame()

Если вы используете анимации в своих веб-приложениях, то вы в любом случае хотите, чтобы они выполнялись как по маслу. И самым простым способом для этого является использование requestAnimationFrame , ну или просто rAF — метода который делает это непринужденно и легко.

Использование этого метода позволяет браузеру справиться с некоторыми затруднительными задачами связанными с анимацией, например такими как управление частотой кадров.

До этого разработчики использовали setTimeout и setInterval , чтобы создавать анимации. Проблема тут была в том, что для того, чтобы анимации были плавными, браузер зачастую отрисовывал кадры быстрее, чем они могут показаться на экране. Что вело к ненужным вычислениям. Также ещё одной проблемой в использовании setInterval или setTimeout было то, что эти анимации продолжали работать, даже если страница не находилась в поле видимости пользователя.

Почему нужно использовать requestAnimationFrame?

Чем же он так хорош requestAnimationFrame ? Давайте посмотрим на некоторые вещи, которые requestAnimationFrame делает значительно лучше, чем setInterval и setTimeout .

Оптимизация браузером

Использование requestAnimationFrame даёт браузеру возможность оптимизировать анимации, чтобы делать их плавнее и более ресурсоэффективными. Не будем сильно вдаваться в детали того, как браузер это делает, просто знайте, что requestAnimationFrame исключает возможность ненужных отрисовок и может связывать вместе несколько анимаций в одно целое и цикл перерисовки.

Анимации работают, когда их видно

Используя requestAnimationFrame ваши анимации будут работать только тогда, когда вкладка со страницей видима пользователю. А это означает меньшее CPU, GPU и использование памяти, что приводит нас к последнему моменту эффективности.

Меньшее потребление питания

Оптимизации, упомянутые в предыдущих двух моментах помогают сократить количество “мусорных процессов”, которые нужно совершить устройству, чтобы создать анимацию и, следовательно, это ведет к бережному энергопотреблению. Это особенно важно для мобильных устройств, которые обычно имеют относительно короткие сроки работы батареи.

Используем requestAnimationFrame

Этому методу должна быть передана колбэк функция, которая отвечает за отрисовку одного кадра вашей анимации. Для того, чтобы создать полную анимацию, вам понадобится сделать этот колбэк рекурсивным.

Временная метка с высоким разрешением DOMHighResTimeStamp передаётся колбэку. Вам не понадобится всегда это использовать, но это может быть довольно полезным для некоторых анимаций.

Пример ниже показывает то, как настроить рекурсивную функцию, которая использует requestAnimationFrame .

Стоит упомянуть, что у вас есть только 16.67 миллисекунд, чтобы отрендерить каждый кадр. С точки зрения времени это не очень хорошо, так что вам нужно быть осторожным с тем, что вы хотите выполнить внутри колбэк функции. Если ваш кадр требует больше 16.67 секунд на обработку, то анимация может выйти не совсем плавной.

requestAnimationFrame отдаст requestID , который может быть использован для отмены запланированного кадра анимации.

Отменяем кадры анимации

Чтобы отменить кадр анимации вы можете использовать метод cancelAnimationFrame . Этот метод должен принять requestID для кадра, который вы хотите отменить.

Позже вы узнаете то, как отслеживать актуальный requestID .

Полифил

Есть великолепный полифилл для requestAnimationFrame , который разработал Эрик Мюллер из Opera и который далее доработали Пол Айриш и Тино Зийдел. Код лежит тут.

Создаём простую демку с requestAnimationFrame

После того, как вы поняли теорию по requestAnimationFrame , давайте создадим простую демку. Вот она.

Подготавливаем HTML и CSS

Откройте свой любимый текстовый редактор и создайте файл под названием index.html . После этого, добавьте следующий код в новый файл.

В этой разметке вы указываете число кнопок, которые будут использоваться для запуска, остановки и сброса анимации. Вы также определите canvas, в котором и будет происходить сама анимация.

Стоит обратить внимание, что тут есть два файла в <script>, который находится в конце этой разметки. raf-polyfill.js это полифил о котором мы говорили в предыдущей секции. Убедитесь в том, что вы скачали этот файл и сохранили его в той же директории, что и index.html . Вам также надо будет скопировать style.css отсюда в папку вашего проекта.

Настраиваем JavaScript

Теперь, как только вы разобрались с HTML и CSS, настало время писать JavaScript код, который будет обрабатывать отрисовку анимации в <canvas> . Если до этого вы не использовали Canvas API, то не беспокойтесь, я объясню всё что нужно по мере прочтения статьи.

Создайте новый файл в папке проекта под название script.js и добавьте туда этот код:

Вы создали три переменные и ассоциировали их с кнопками из разметки.

Дальше вам надо написать немного кода, чтобы настроить Canvas. Скопируйте этот код в свой script.js файл.

Тут сначала мы создаем переменную под названием сanvas и ассоциируем её с элементом из разметки. Далее вы задаёте 2d контекст отрисовки для него. Это даёт нам методы для отрисовки объектов на нём, так же как и методы контроля стилей этих объектов.

Следующая строка кода выставляет свойству fillStyle для контекста отрисовки #212121 .

requestID переменная будет использоваться, чтобы отслеживать requestID , возвращенный методом requestAnimationFrame .

Переменные posX , boxWidth и pixelPerFrame используются для выставления позиции блоку при отрисовке; ширина блока; и число пикселей на которое блок должен двигаться при каждом кадре.

Под конец вы вызываете контекст отрисовки методом fillReact , передав ему X и Y координаты положения прямоугольника вместе с его высотой и шириной.

Написание анимированной функции

Далее вам надо написать функцию animate , которая будет ответственна за прорисовку кадров.

Скопируйте следующий код в ваш script.js файл.

Вызов requestAnimateFrame вверху функции запланирует следующий кадр анимации. Он размещается сначала, так как мы можем подобраться как можно ближе к 60 FPS, при использовании setTimeout фолбэка, которое применяет полифил.

Далее у вас будет if проверка, которая проверяет достиг ли блок крайней правой стороны canvas’а. Если блок ещё этого не сделал, то вы используете clearRect метод, чтобы удалить блок, отрисованный в предыдущем кадре и затем отрисовать блок на новой позиции с использованием fillRect . Если же блок достиг конца canvas’а, то вы вызываете cancelAnimationFrame , чтобы отменить планирование кадра в начале animate функции. И под конец, вы обновляете posX переменную с позицией на которой блок должен быть отрисован при следующем кадре.

Цепляем кнопки

Последнее, что нам нужно сделать для того, чтобы демо работало — это настроить срабатывания по событиям для кнопок старта, остановки и сброса. Добавьте следующий код в ваш script.js файл.

Тут у нас три обработчика событий. Первые два запускают и останавливают анимацию, а последний запускается при нажатии на кнопку reset. Это выставит переменной posX значение 0 . Также это очистит canvas — мы не так сильно обеспокоены производительностью, так что это нормально делать таким ленивым способом — и отрисовывать блок обратно на его стартовой позиции.

Name already in use

javascript-tutorial-ru / 1-js / 7-js-misc / 3-settimeout-setinterval / article.md

  • Go to file T
  • Go to line L
  • Copy path
  • Copy permalink
  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

setTimeout и setInterval

Почти все реализации JavaScript имеют внутренний таймер-планировщик, который позволяет задавать вызов функции через заданный период времени.

В частности, эта возможность поддерживается в браузерах и в сервере Node.JS.

func/code : Функция или строка кода для исполнения. Строка поддерживается для совместимости, использовать её не рекомендуется.

delay : Задержка в миллисекундах, 1000 миллисекунд равны 1 секунде.

arg1 , arg2 . : Аргументы, которые нужно передать функции. Не поддерживаются в IE9-.

Исполнение функции произойдёт спустя время, указанное в параметре delay .

Например, следующий код вызовет func() через одну секунду:

С передачей аргументов (не сработает в IE9-):

Если первый аргумент является строкой, то интерпретатор создаёт анонимную функцию из этой строки.

То есть такая запись тоже сработает:

Однако, использование строк не рекомендуется, так как они могут вызвать проблемы при минимизации кода, и, вообще, сама возможность использовать строку сохраняется лишь для совместимости.

Вместо них используйте анонимные функции, вот так:

Отмена исполнения clearTimeout

Функция setTimeout возвращает числовой идентификатор таймера timerId , который можно использовать для отмены действия.

В следующем примере мы ставим таймаут, а затем удаляем (передумали). В результате ничего не происходит.

Как видно из alert , в браузере идентификатор таймера является обычным числом. Другие JavaScript-окружения, например Node.JS, могут возвращать объект таймера, с дополнительными методами.

Такие разночтения вполне соответствуют стандарту просто потому, что в спецификации JavaScript про таймеры нет ни слова.

Таймеры — это надстройка над JavaScript, которая описана в секции Timers стандарта HTML5 для браузеров и в документации к Node.JS — для сервера.

Метод setInterval имеет синтаксис, аналогичный setTimeout .

Смысл аргументов — тот же самый. Но, в отличие от setTimeout , он запускает выполнение функции не один раз, а регулярно повторяет её через указанный интервал времени. Остановить исполнение можно вызовом clearInterval(timerId) .

Следующий пример при запуске станет выводить сообщение каждые две секунды, пока не пройдёт 5 секунд:

Важная альтернатива setInterval — рекурсивный setTimeout :

В коде выше следующее выполнение планируется сразу после окончания предыдущего.

Рекурсивный setTimeout — более гибкий метод тайминга, чем setInterval , так как время до следующего выполнения можно запланировать по-разному, в зависимости от результатов текущего.

Например, у нас есть сервис, который раз в 5 секунд опрашивает сервер на предмет новых данных. В случае, если сервер перегружен, можно увеличивать интервал опроса до 10, 20, 60 секунд. А потом вернуть обратно, когда всё нормализуется.

Если у нас регулярно проходят грузящие процессор задачи, то мы можем оценивать время, потраченное на их выполнение, и планировать следующий запуск раньше или позже.

Рекурсивный setTimeout гарантирует паузу между вызовами, setInterval — нет.

Давайте сравним два кода. Первый использует setInterval :

Второй использует рекурсивный setTimeout :

При setInterval внутренний таймер будет срабатывать чётко каждые 100 мс и вызывать func(i) :

Вы обратили внимание.

Реальная пауза между вызовами func при setInterval меньше, чем указана в коде!

Это естественно, ведь время работы функции никак не учитывается, оно «съедает» часть интервала.

Возможно и такое что func оказалась сложнее, чем мы рассчитывали и выполнялась дольше, чем 100 мс.

В этом случае интерпретатор будет ждать, пока функция завершится, затем проверит таймер и, если время вызова setInterval уже подошло (или прошло), то следующий вызов произойдёт сразу же.

Если функция и выполняется дольше, чем пауза setInterval , то вызовы будут происходить вообще без перерыва.

Исключением является IE, в котором таймер «застывает» во время выполнения JavaScript.

А так будет выглядеть картинка с рекурсивным setTimeout :

При рекурсивном setTimeout задержка всегда фиксирована и равна 100 мс.

Это происходит потому, что каждый новый запуск планируется только после окончания текущего.

Минимальная задержка таймера

У браузерного таймера есть минимальная возможная задержка. Она меняется от примерно нуля до 4 мс в современных браузерах. В более старых она может быть больше и достигать 15 мс.

По стандарту, минимальная задержка составляет 4 мс. Так что нет разницы между setTimeout(. 1) и setTimeout(. 4) .

Посмотреть минимальное разрешение «вживую» можно на следующем примере.

В примере ниже каждая полоска удлиняется вызовом setInterval с указанной на ней задержкой — от 0 мс (сверху) до 20 мс (внизу).

Позапускайте его в различных браузерах. Вы заметите, что несколько первых полосок анимируются с одинаковой скоростью. Это как раз потому, что слишком маленькие задержки таймер не различает.

[iframe border=»1″ src=»https://github.com/iliakan/javascript-tutorial-ru/blob/master/1-js/7-js-misc/3-settimeout-setinterval/setinterval-anim» link edit]

Реальная частота срабатывания

В ряде ситуаций таймер будет срабатывать реже, чем обычно. Задержка между вызовами setInterval(. 4) может быть не 4 мс, а 30 мс или даже 1000 мс.

Большинство браузеров (десктопных в первую очередь) продолжают выполнять setTimeout/setInterval , даже если вкладка неактивна.

При этом ряд из них (Chrome, FF, IE10) снижают минимальную частоту таймера, до 1 раза в секунду. Получается, что в «фоновой» вкладке будет срабатывать таймер, но редко.

При работе от батареи, в ноутбуке — браузеры тоже могут снижать частоту, чтобы реже выполнять код и экономить заряд батареи. Особенно этим известен IE. Снижение может достигать нескольких раз, в зависимости от настроек.

При слишком большой загрузке процессора JavaScript может не успевать обрабатывать таймеры вовремя. При этом некоторые запуски setInterval будут пропущены.

Вывод: на частоту 4 мс стоит ориентироваться, но не стоит рассчитывать.

Разбивка долгих скриптов

Нулевой или небольшой таймаут также используют, чтобы разорвать поток выполнения «тяжелых» скриптов.

Например, скрипт для подсветки синтаксиса должен проанализировать код, создать много цветных элементов для подсветки и добавить их в документ — на большом файле это займёт много времени, браузер может даже подвиснуть, что неприемлемо.

Для того, чтобы этого избежать, сложная задача разбивается на части, выполнение каждой части запускается через мини-интервал после предыдущей, чтобы дать браузеру время.

Например, осуществляется анализ и подсветка первых 100 строк, затем через 20 мс — следующие 100 строк и так далее. При этом можно подстраиваться под CPU посетителя: замерять время на анализ 100 строк и, если процессор хороший, то в следующий раз обработать 200 строк, а если плохой — то 50. В итоге подсветка будет работать с адекватной быстротой и без тормозов на любых текстах и компьютерах.

  • Методы setInterval(func, delay) и setTimeout(func, delay) позволяют запускать func регулярно/один раз через delay миллисекунд.
  • Оба метода возвращают идентификатор таймера. Его используют для остановки выполнения вызовом clearInterval/clearTimeout .
  • В случаях, когда нужно гарантировать задержку между регулярными вызовами или гибко её менять, вместо setInterval используют рекурсивный setTimeout .
  • Минимальная задержка по стандарту составляет 4 мс . Браузеры соблюдают этот стандарт, но некоторые другие среды для выполнения JS, например Node.JS, могут предоставить и меньше задержки.
  • В реальности срабатывания таймера могут быть гораздо реже, чем назначено, например если процессор перегружен, вкладка находится в фоновом режиме, ноутбук работает от батареи или по какой-то иной причине.

Браузерных особенностей почти нет, разве что вызов setInterval(. 0) с нулевой задержкой в IE недопустим, нужно указывать setInterval(. 1) .

Похожие статьи