setTimeout или setInterval?

Насколько я могу судить, эти две части javascript ведут себя одинаково:

Вариант А:

function myTimeoutFunction()
{
    doStuff();
    setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

Вариант Б:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Есть ли разница между использованием setTimeout и setInterval?


person Damovisa    schedule 08.04.2009    source источник
comment
Если вам нужны подробные сведения о том, как работают таймеры в JS, Джон Ресиг написал хороший статья по этой теме   -  person Rafael    schedule 08.04.2009
comment
есть также очевидная разница в том, что setTimeout требует, чтобы эта дополнительная строка кода продолжала распространяться, что имеет недостаток в том, что это проблема обслуживания, но преимущество в том, что вы можете легко изменить период   -  person annakata    schedule 09.04.2009
comment
попробуйте этот jsfiddle.net/pramendra/Y4vEV   -  person Pramendra Gupta    schedule 27.01.2011
comment
Спасибо @JapanPro, но у меня никогда не было проблем с работой тайм-аутов. Этот пост был о том, в чем разница и что следует использовать.   -  person Damovisa    schedule 28.01.2011


Ответы (19)


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

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

В этом скрипте вы можете ясно видеть, что тайм-аут будет отставать, а интервал почти полностью время почти при 1 вызове в секунду (что пытается сделать скрипт). Если вы измените переменную скорости вверху на что-то маленькое, например 20 (что означает, что он будет пытаться работать 50 раз в секунду), интервал никогда не достигнет в среднем 50 итераций в секунду.

Задержка почти всегда незначительна, но если вы программируете что-то действительно точное, вам следует использовать саморегулирующийся таймер (который по сути является таймером на основе тайм-аута, который постоянно настраивается на задержку, на которую он созданный)

person David Snabel-Caunt    schedule 08.04.2009
comment
У Энди было аналогичное предложение. Гипотетически, означает ли это, что если для выполнения метода требуется более 1000 мс, у вас может быть более одного запущенного одновременно? - person Damovisa; 08.04.2009
comment
Теоретически да. На практике нет, поскольку Javascript не поддерживает многопоточность. Если ваш код занимает больше 1000 мс, он заморозит браузер. - person Kamiel Wanrooij; 08.04.2009
comment
Технически код не будет выполняться точно каждые 1000 мс, поскольку это зависит от разрешения таймера и от того, выполняется ли уже другой код. Тем не менее, ваша точка зрения остается в силе. - person Matthew Crumley; 08.04.2009
comment
Обратите внимание, что интервал по-прежнему может быть отложен или пропущен, если вы не обслуживаете его вовремя (см. Ниже). - person bobince; 09.04.2009
comment
setInterval отличается двумя способами: 1. setInterval не является рекурсивным, и setInterval в первый раз вызовет вашу функцию по истечении указанного времени, в то время как setTimeout будет вызван в первый раз без какой-либо задержки, и после этого он вызовет снова после указанного времени. После первого исполнения они работают почти так же. - person Hafiz; 02.12.2011
comment
Разница в том, что setTimeout не повторяется. Это позволяет вам запустить сценарий по истечении установленного времени, но только один раз. С другой стороны, setInterval будет повторять этот сценарий, пока он не будет остановлен с помощью clearTimeout (). - person Leander; 13.05.2013
comment
Также у нас есть контроль по длине периода тайм-аута в setTimeout, в setInterval нет ... И действительно нет разницы между clearTimeout и clearInterval - person vp_arth; 28.03.2014

Есть ли разница?

да. Тайм-аут выполняется через определенное время после вызова setTimeout (); Интервал выполняется через определенное время после срабатывания предыдущего интервала.

Вы заметите разницу, если выполнение вашей функции doStuff () займет некоторое время. Например, если мы представляем вызов setTimeout / setInterval с ., запуск тайм-аута / интервала с * и выполнение кода JavaScript с [-----], временные шкалы будут выглядеть так:

Timeout:

.    *  .    *  .    *  .    *  .
     [--]    [--]    [--]    [--]

Interval:

.    *    *    *    *    *    *
     [--] [--] [--] [--] [--] [--]

Следующее осложнение - если интервал срабатывает, когда JavaScript уже чем-то занят (например, обрабатывает предыдущий интервал). В этом случае интервал запоминается и происходит, как только предыдущий обработчик завершает работу и возвращает управление браузеру. Так, например, для процесса doStuff (), который иногда бывает коротким ([-]), а иногда и длинным ([-----]):

.    *    *    •    *    •    *    *
     [-]  [-----][-][-----][-][-]  [-]

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

Таким образом, интервалы пытаются «наверстать упущенное», чтобы вернуться к расписанию. Но они не ставятся в очередь друг на друга: в каждом интервале может быть только одно ожидающее выполнение. (Если бы все они выстраивались в очередь, в браузере оставался бы постоянно расширяющийся список невыполненных выполнений!)

.    *    •    •    x    •    •    x
     [------][------][------][------]

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

Если выполнение вашей функции doStuff () обычно занимает больше времени, чем установленный для нее интервал, браузер потребляет 100% ресурсов ЦП, пытаясь его обслужить, и может стать менее отзывчивым.

Что вы используете и почему?

Chained-Timeout дает браузеру гарантированный промежуток свободного времени; Interval пытается обеспечить выполнение выполняемой функции как можно ближе к запланированному времени за счет доступности пользовательского интерфейса браузера.

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

С точки зрения совместимости браузеров, setTimeout предшествует setInterval, но все браузеры, с которыми вы встретитесь сегодня, поддерживают оба. Последним проигравшим за многие годы был IE Mobile в WinMo ‹6.5, но, надеюсь, он тоже остался позади.

person bobince    schedule 08.04.2009
comment
Но верна ли причина выбора между Interval и Timeout даже на небраузерных платформах, таких как, например, WebOS или JIL? - person Vid L; 22.11.2009
comment
Хороший способ связать таймауты для анонимных функций: setTimeout (function () {setTimeout (arguments.callee, 10)}, 10) - person Justin Meyer; 25.06.2010
comment
С точки зрения совместимости браузеров, хотя все браузеры предоставляют оба метода, их производительность разная. - person unigg; 07.10.2010
comment
Но тогда есть вероятность, что он не поддерживает ничего другого, что вы используете, так что очень верно - person Basic; 23.06.2011
comment
драм-машина от проекта Chrome с использованием setTimeout (schedule (), 0); Таким образом, в браузере не будет ненужного стека, когда это фоновая вкладка для хрома или недостатка ресурсов. - person Elliot Yap; 23.02.2012
comment
Когда вы говорите, что интервал уменьшается ... вы имеете в виду, что это конкретное время ... т.е. если у меня есть 100 интервалов ... все они действительно будут работать в какой-то момент. Дроп просто означает, что некоторые побегут позже, если их не уронили? - person ; 22.03.2013
comment
@JustinMeyer в то время использование arguments.callee было отличным решением. Использование этого метода сейчас устарело. . Хотя именованные функции приемлемы. - person Marc; 27.04.2018

setInterval ()

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

Если вы хотите зациклить код для анимации или по такту часов, используйте setInterval().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setInterval(doStuff, 5000);

setTimeout ()

setTimeout() - это метод выполнения кода, основанный на времени, который будет выполнять сценарий только один раз при достижении интервала. Он не повторится снова, если вы не настроите его на цикл сценария, вложив объект setTimeout() внутри функции, которую он вызывает для запуска. Если он настроен на цикл, он будет продолжать срабатывать с интервалом, если вы не вызовете clearTimeout().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setTimeout(doStuff, 5000);

Если вы хотите, чтобы что-то произошло один раз по прошествии определенного периода времени, используйте setTimeout(). Это потому, что он выполняется только один раз при достижении указанного интервала.

person Haris N I    schedule 14.08.2013
comment
Хорошее объяснение, но обратите внимание, что OP понимает основную разницу в примерах, предоставленных OP. В частности, обратите внимание, что в примере OP setTimeout() setTimeout() вызывается рекурсивно, а setInterval() - нет. - person DavidRR; 04.06.2014

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

var timerId = null;
function myTimeoutFunction()
{
    doStuff();
    timerId = setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

// later on...
clearTimeout(timerId);

против

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
var timerId = setInterval(myTimeoutFunction, 1000);

// later on...
clearInterval(timerId);
person Kamiel Wanrooij    schedule 08.04.2009
comment
Я не понимаю, как вы не отслеживаете идентификатор таймера в случае setInterval. Просто из функции вытащили. - person Kekoa; 21.03.2010
comment
Другой вариант с setTimeout - вместо сохранения идентификатора добавить оператор if, чтобы установить следующий тайм-аут только при выполнении некоторого условия. - person nnnnnn; 22.06.2011
comment
Кекоа, хорошее замечание. Но вам нужно сохранить идентификатор интервала только один раз. Идентификатор тайм-аута, вероятно, меняется при каждом вызове, поэтому вы должны отслеживать эти изменения. Код, который хочет очистить тайм-аут, должен каким-то образом иметь доступ к текущему значению этой переменной. Кроме того, невозможно очистить тайм-аут во время работы doStuff, потому что идентификатор недействителен. Однако на самом деле нет необходимости сохранять идентификаторы тайм-аута. Вместо этого вы можете просто перестать звонить setTimeout. - person Robert; 08.07.2011
comment
По моему опыту, в большинстве случаев вы хотите иметь возможность отмены даже при использовании setTimeout. В 99% случаев вы хотите отменить до следующего вызова, а не после завершения следующего. - person Kamiel Wanrooij; 11.07.2011

Я считаю, что метод setTimeout проще использовать, если вы хотите отменить тайм-аут:

function myTimeoutFunction() {
   doStuff();
   if (stillrunning) {
      setTimeout(myTimeoutFunction, 1000);
   }
}

myTimeoutFunction();

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

person Guffa    schedule 08.04.2009

Сама разница в их целях.

setInterval()
   -> executes a function, over and over again, at specified time intervals  

setTimeout()
   -> executes a function, once, after waiting a specified number of milliseconds

Это так просто

Более подробная информация представлена ​​здесь, http://javascript.info/tutorial/settimeout-setinterval.

person kmario23    schedule 11.01.2014
comment
Хорошее краткое объяснение, но обратите внимание, что OP понимает основную разницу в примерах, предоставленных OP. В частности, обратите внимание, что в примере OP setTimeout() setTimeout() вызывается рекурсивно, а setInterval() - нет. - person DavidRR; 04.06.2014

Когда вы запускаете какую-то функцию внутри setInterval, которая работает больше времени, чем timeout->, браузер зависнет.

- Например, doStuff () занимает 1500 секунд. для выполнения, и вы выполните: setInterval (doStuff, 1000);
1) Браузер запускает doStuff (), который занимает 1,5 секунды. быть исполненным;
2) Через ~ 1 секунду он снова пытается запустить doStuff (). Но предыдущий doStuff () по-прежнему выполняется-> поэтому браузер добавляет этот запуск в очередь (для запуска после того, как первый будет выполнен).
3,4, ..) То же добавление в очередь выполнения для следующих итераций, но doStuff () из предыдущей все еще выполняется ...
Поскольку результат - браузер зависает.

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

person Serg Hospodarets    schedule 26.04.2014
comment
Я не знаю, почему никто не нашел в этом ответе никакой ценности! - person Randika Vishman; 30.10.2015

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

function myTimeoutFunction()
{
    setTimeout(myTimeoutFunction, 1000);
    doStuff();
}
myTimeoutFunction()

После этого изменения он будет равен

function myTimeoutFunction()
{
    doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Но стабильного результата все равно не будет, потому что JS однопоточный. На данный момент, если поток JS будет чем-то занят, он не сможет выполнить вашу функцию обратного вызова, и выполнение будет отложено на 2-3 мс. Если у вас 60 выполнений в секунду, и каждый раз, когда у вас случайная задержка в 1-3 секунды, это будет абсолютно неприемлемо (через одну минуту это будет задержка около 7200 мсек), и я могу посоветовать использовать что-то вроде этого:

    function Timer(clb, timeout) {
        this.clb = clb;
        this.timeout = timeout;
        this.stopTimeout = null;
        this.precision = -1;
    }

    Timer.prototype.start = function() {
        var me = this;
        var now = new Date();
        if(me.precision === -1) {
            me.precision = now.getTime();
        }
        me.stopTimeout = setTimeout(function(){
            me.start()
        }, me.precision - now.getTime() + me.timeout);
        me.precision += me.timeout;
        me.clb();
    };

    Timer.prototype.stop = function() {
        clearTimeout(this.stopTimeout);
        this.precision = -1;
    };

    function myTimeoutFunction()
    {
        doStuff();
    }

    var timer = new Timer(myTimeoutFunction, 1000);
    timer.start();

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

person degr    schedule 24.12.2016

Я использую setTimeout.

Очевидно, разница в том, что setTimeout вызывает метод один раз, setInterval вызывает его многократно.

Вот хорошая статья, объясняющая разницу: Учебник: таймеры JavaScript с setTimeout и setInterval

person Bravax    schedule 08.04.2009
comment
Да, разница есть, но два кода, которые я предоставил, должны делать то же самое ... - person Damovisa; 08.04.2009
comment
Эммм да ... я бы подумал ... но, судя по dcaunt и его подсчету голосов, это не совсем то, что происходит. - person Bravax; 08.04.2009

Я провел простой тест setInterval(func, milisec), потому что мне было любопытно, что происходит, когда потребление времени функции превышает продолжительность интервала.

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

Я тестировал это на Chrome v23. Я надеюсь, что это детерминированная реализация во всех современных браузерах.

window.setInterval(function(start) {
    console.log('fired: ' + (new Date().getTime() - start));
    wait();
  }, 1000, new Date().getTime());

Вывод в консоль:

fired: 1000    + ~2500 ajax call -.
fired: 3522    <------------------'
fired: 6032
fired: 8540
fired: 11048

Функция wait - это просто помощник по блокировке потоков - синхронный вызов ajax, который занимает ровно 2500 миллисекунд обработки на стороне сервера:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
person jwaliszko    schedule 25.11.2012
comment
нет ситуации с параллельными итерациями - да, это должно быть невозможно. Клиентский JavaScript имеет однопоточную модель выполнения, поэтому ничего (обработчики событий и т. Д.) Никогда не происходит одновременно. Вот почему во время синхронного вызова ajax ничего не происходит (и браузер не отвечает). - person MrWhite; 29.11.2012
comment
Отвечает ли браузер за несколько миллисекунд между интервалами? Сработает ли другое событие, если оно ожидается? (Спасибо за тесты кстати +1) - person MrWhite; 29.11.2012
comment
Согласно MDN, это считается опасным использованием, если функция могла выполняться дольше, чем интервал времени. Рекурсивный вызов setTimout является предпочтительным. - person MrWhite; 03.12.2012

Оба setInterval и setTimeout возвращают идентификатор таймера, который можно использовать для отмены выполнения, то есть до того, как сработают таймауты. Для отмены вы вызываете clearInterval или clearTimeout следующим образом:

var timeoutId = setTimeout(someFunction, 1000);
clearTimeout(timeoutId);
var intervalId = setInterval(someFunction, 1000),
clearInterval(intervalId);

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

person Helgi    schedule 08.04.2009

Чтобы взглянуть на это немного по-другому: setInterval гарантирует, что код запускается с каждым заданным интервалом (т.е. 1000 мс, или сколько вы указываете), а setTimeout устанавливает время, в течение которого он «ждет, пока» он выполнит код. А поскольку для запуска кода требуются дополнительные миллисекунды, он добавляет 1000 мс, и, таким образом, setTimeout запускается снова с неточным временем (более 1000 мс).

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

person CatalinBerta    schedule 27.01.2015

Вы можете проверить ответ bobince самостоятельно, запустив следующий JavaScript или проверив этот JSFiddle

<div id="timeout"></div>
<div id="interval"></div>

var timeout = 0;
var interval = 0;

function doTimeout(){
    $('#timeout').html(timeout);
    timeout++;
    setTimeout(doTimeout, 1);
}

function doInterval(){
    $('#interval').html(interval);
    interval++;
}

$(function(){
    doTimeout();
    doInterval();
    setInterval(doInterval, 1);
});
person Gudradain    schedule 17.11.2014

Что ж, setTimeout лучше в одной ситуации, как я только что узнал. Я всегда использую setInterval, который мне оставил работать в фоновом режиме более получаса. Когда я вернулся на эту вкладку, слайд-шоу (в котором использовался код) менялось очень быстро, а не каждые 5 секунд, как должно было быть. На самом деле это происходит снова, когда я тестирую это больше, и неважно, виноват ли браузер или нет, потому что с setTimeout такая ситуация совершенно невозможна.

person Nino    schedule 18.10.2011
comment
Похоже, вы вызвали setInterval внутри вызываемой функции. Вот как вы выполняете цикл с setTimeout, но с setInterval вы фактически создаете совершенно новый цикл каждый раз, когда он вызывается. - person Stephen R; 10.02.2017

В консоли разница очевидна:

введите описание изображения здесь

person testCoder    schedule 04.01.2014

Просто добавляю то, что уже было сказано, но версия кода setTimeout также достигнет Maximum call stack size, что остановит его работу. Поскольку для рекурсивной функции нет базового случая, на котором можно было бы остановиться, вы не можете заставить ее работать вечно.

person Maaz    schedule 26.05.2014
comment
Я не думаю, что это правда. См. Здесь stackoverflow.com/questions/8058612/ - person Kevin Wheeler; 13.06.2015

Если вы установите слишком короткий интервал в setInterval, он может сработать до завершения предыдущего вызова функции. Я столкнулся с этой проблемой в недавнем браузере (Firefox 78). Это привело к тому, что сборщик мусора не смог достаточно быстро освободить память и создал огромную утечку памяти. Использование setTimeout(function, 500); дало сборке мусора достаточно времени, чтобы очистить и сохранить стабильность памяти с течением времени.

Серг Хосподарец упомянул проблему в своем ответе, и я полностью согласен с его замечаниями, но он не включил проблему утечки памяти / сбора мусора. Я тоже испытал некоторое зависание, но использование памяти мгновенно увеличилось до 4 ГБ для выполнения какой-то незначительной задачи, что было для меня настоящим обломом. Таким образом, я думаю, что этот ответ по-прежнему полезен для других в моей ситуации. Я бы поставил это в комментарии, но у меня нет репутации для этого. Надеюсь, ты не против.

person Max M.    schedule 06.07.2020

Кажется, что вариант A и вариант B работают одинаково, в основном из-за мест, где расположены функции setInterval и setTimeout.

function myTimeoutFunction()
{
    doStuff();
    setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

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

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

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

So which one should you use?

Из вышесказанного вы, вероятно, сможете сделать вывод, что лучший вариант - setInterval.

person Einsteinium    schedule 11.03.2021

Я думаю, SetInterval и SetTimeout разные. SetInterval выполняет блок в соответствии с установленным временем, а SetTimeout выполняет блок кода один раз.

Попробуйте этот набор кодов после секунд обратного отсчета тайм-аута:

setInterval(function(e){
    alert('Ugbana Kelvin');
}, 2000);

а потом попробуй

setTimeout(function(e){
    alert('Ugbana Kelvin');
}, 2000);

Вы можете сами увидеть различия.

person Ugbana Chukwujindu Kelvin    schedule 17.04.2013
comment
Это не ответ на вопрос. settimeout () можно использовать рекурсивно для получения того же результата, что и setinterval. Вопрос был в производительности этих двух вариантов. - person Tomas Gonzalez; 18.01.2016