setTimeout або setInterval?


763

Наскільки я можу сказати, ці дві частини Javascript поводяться однаково:

Варіант A:

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

myTimeoutFunction();

Варіант B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Чи є різниця між використанням setTimeout та setInterval ?


6
Якщо ви хочете отримати якісь детальні відомості про те, як працюють таймери в JS, Джон Ресіг написав хорошу статтю на цю тему
Рафаель

9
Є також очевидна різниця, що setTimeout вимагає додаткового рядка коду, щоб він поширювався, який має недолік, що є проблемою з технічним обслуговуванням, але користь дозволяє легко змінити період
annakata


4
Дякую @JapanPro, але у мене ніколи не було проблем з тим, як працювати з таймаутами. Цей пост розповідав про те, у чому різниця і яку слід використовувати.
Дамовіса

Відповіді:


670

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

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

У цій скрипці ви чітко бачите, що час очікування відставатиме, тоді як інтервал майже весь час складає майже 1 виклик / секунду (що намагається зробити сценарій). Якщо ви зміните змінну швидкості вгорі на щось маленьке, як 20 (тобто це буде намагатися запустити 50 разів на секунду), інтервал ніколи не досягне в середньому 50 ітерацій в секунду.

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


4
Енді мав подібну пропозицію. Гіпотетично чи означає це, що якщо для виконання методу потрібно більше 1000 мс, ви можете одночасно працювати більше одного?
Дамовіса

14
Теоретично, так. На практиці ні, оскільки Javascript не підтримує багатопотоковість. Якщо ваш код займає більше 1000 мс, він застигне браузер.
Kamiel Wanrooij

61
Технічно код не виконується рівно кожні 1000 мс, оскільки це залежить від роздільної здатності таймера та того, чи вже виконується інший код. Ваша думка все ще стоїть.
Меттью Крамлі

10
setInterval відрізняється двома способами, 1. setInterval не є рекурсивним і setInterval вперше зателефонує вашій функції після вказаного часу, тоді як setTimeout вперше буде викликаний без будь-якої затримки, після чого він повторно зателефонує після зазначеного часу. Після першого виконання вони працюють майже так само.
Хафіз

5
Різниця полягає в тому, що setTimeout не повторюється. Це дозволяє запускати сценарій через встановлений час, але лише один раз. SetInterval з іншого боку повторить цей сценарій, доки він не зупиниться з clearTimeout ().
Leander

648

Чи є різниця?

Так. Час очікування виконує певний час після виклику 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, але, сподіваємось, це теж зараз за нами.


Але чи є причина вибору між Interval та Timeout справжньою навіть не-браузерною платформою, як, наприклад, WebOS або JIL?
Вид Л

2
Хороший спосіб робити приковані тайм-аути на анонімних функціях: setTimeout (function () {setTimeout (argument.callee, 10)}, 10)
Джастін Мейєр

1
Що стосується сумісності браузера, хоча всі браузери пропонують обидва методи, їх ефективність різна.
unigg

"Але, швидше за все, це те, що він не підтримує нічого іншого, що ви також використовуєте", так дуже вірно
Basic

1
барабанна машина за проектом хрому з використанням setTimeout ("графік ()", 0); Таким чином, у браузера не буде зайвого стека, коли він знаходиться на вкладці фону для хромування або відсутності ресурсів.
Елліот Яп

91

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(). Це тому, що воно виконується лише один раз, коли досягнутий визначений інтервал.


6
Приємне пояснення, але зауважте, що ОП розуміє основну різницю в прикладах, які надає ОП. Зокрема, зауважте, що у setTimeout()прикладі ОП setTimeout()називається рекурсивно , тоді setInterval()як ні.
DavidRR

44

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);

35
Я не бачу, як ви не відстежуєте ідентифікатор таймера у випадку setInterval. Це просто витягнуто з функції.
Кекоа

1
Інший варіант з setTimeout, а не збереження id add ifоператора, щоб встановити наступний час очікування лише тоді, коли деяка умова справдиться.
nnnnnn

7
Кекоа, хороший момент. Але вам потрібно зберегти ідентифікатор інтервалу лише один раз. Ідентифікатор таймауту, ймовірно, змінюється з кожним викликом, тому вам доведеться слідкувати за цими змінами. Код, який хоче очистити час очікування, повинен якось мати доступ до поточного значення цієї змінної. Крім того, неможливо зняти час очікування під час запуску, doStuffоскільки ідентифікатор недійсний. Однак економити ідентифікатори часу не потрібно. Натомість ви можете просто припинити дзвінки setTimeout.
Роберт

4
На мій досвід, більшу частину часу ви хочете мати можливість скасувати навіть під час використання setTimeout. 99% часу, яке ви хочете скасувати до наступного виклику, а не після закінчення наступного.
Kamiel Wanrooij

23

Я вважаю setTimeoutметод простішим у використанні, якщо ви хочете скасувати тайм-аут:

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

myTimeoutFunction();

Крім того, якщо щось піде не так у функції, воно просто перестане повторюватися при першій помилці, а не повторювати помилку щосекунди.


20

Сама різниця полягає в їх цілях.

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


7
Приємне стисле пояснення, але зауважте, що ОП розуміє основну відмінність у прикладах, які надає ОП. Зокрема, зауважте, що у setTimeout()прикладі ОП setTimeout()називається рекурсивно , тоді setInterval()як ні.
DavidRR

14

Якщо ви запускаєте якусь функцію всередині setInterval, яка працює більше часу, ніж timeout-> браузер буде застряг.

- Наприклад, doStuff () займає 1500 сек. виконується і ви робите: setInterval (doStuff, 1000);
1) Запуск браузера doStuff (), який займає 1,5 сек. виконувати;
2) Через ~ 1 секунду він намагається запустити doStuff () ще раз. Але попередній doStuff () все ще виконується-> тому браузер додає цей запуск до черги (для запуску після того, як буде зроблено перший).
3,4, ..) Те саме додавання до черги виконання для наступних ітерацій, але doStuff () від попереднього все ще триває ...
Як результат - браузер застряг.

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


1
Я не знаю, чому ніхто не знайшов жодної цінності у цій відповіді!
Рандіка Вішман

9

Я використовую setTimeout.

Мабуть, різниця setTimeout викликає метод один раз, setInterval викликає його повторно.

Ось гарна стаття, що пояснює різницю: Підручник: таймери JavaScript з setTimeout та setInterval


2
Так, я зрозумів цю різницю, але два коди, які я надав, повинні робити те саме ...
Дамовіса

Так, я б міг подумати ... але, за словами декана та його підрахунку голосів, це відбувається не зовсім так.
Бравакс

9

Ваш код матиме різні види виконання, і в деяких проектах, таких як онлайн-ігри, це не прийнятно. По-перше, що вам потрібно зробити, щоб ваш код працював з однаковими цілями, слід змінити "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 мсек, а результат буде стабільним.


7

Я зробив простий тест на 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
    });
}

1
"жодна ситуація з паралельними ітераціями не працює" - так, це має бути неможливим. Клієнтський JavaScript має єдину модель виконання потоків, тому нічого (обробники подій тощо) ніколи не відбувається одночасно. Ось чому нічого не відбувається (а браузер не реагує) під час синхронного дзвінка Ajax.
MrWhite

Чи браузер реагує на кілька мс між "інтервалами"? Чи буде інша пожежа, якщо це очікується? (Спасибі за тести btw +1)
MrWhite

1
Згідно з MDN, це вважається " небезпечним використанням ", якщо функція може виконуватись більше, ніж інтервал часу. Рекурсивний setTimoutдзвінок є кращим.
MrWhite

6

Щоб подивитися на це трохи інакше: setInterval гарантує, що код запускається на кожному заданому інтервалі (тобто 1000 мс, або скільки ви вказали), а setTimeout встановлює час, який він "чекає, поки" запустить код. А оскільки для запуску коду потрібно додаткові мілісекунди, він додає до 1000 мс, і, таким чином, setTimeout запускається знову у неточний час (понад 1000 мс).

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


5

І setInterval, і setTimeout повертають ідентифікатор таймера, який ви можете використовувати для скасування виконання, тобто до запуску тайм-аутів. Щоб скасувати, ви дзвоните або clearInterval, або clearTimeout так:

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

Також тайм-аути автоматично скасовуються, коли ви залишаєте сторінку або закриваєте вікно браузера.


4

Ви можете перевірити відповідь 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);
});

3

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


Здається, що ви викликали setInterval всередині функції, яку ви викликали. Ось так ви цикла за допомогою setTimeout, але за допомогою setInterval ви створюєте абсолютно новий цикл кожного разу, коли він викликається.
Stephen R


2

Просто додавання до вже сказаного, але версія коду setTimeout також досягне того, Maximum call stack sizeщо зупинить його функціонування. Оскільки не існує базового випадку, щоб рекурсивна функція зупинилася, тому ви не можете її запустити назавжди.


Я не думаю, що це правда. Дивіться тут stackoverflow.com/questions/8058612/…
Кевін Уілер

-1

Найбільш загальна різниця між і setInterval (вираз, тривалість) полягає в тому

setTimeout () буде виконувати вираз тільки ONCE і після цього після вказаної тривалості.

Однак,

setInterval () виконає вираз у INFINITE-LOOP після кожної заданої тривалості.


-5

Я думаю SetIntervalі SetTimeoutбувають різні. SetIntervalвиконує блок відповідно до часу, встановленого в той час, SetTimeoutвиконує блок коду один раз.

Спробуйте скористатися цими наборами кодів після секунд відліку часу:

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

а потім спробуйте

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

Ви можете бачити відмінності для себе.


Це не дає відповіді на запитання. settimeout () може використовуватися рекурсивно, щоб дати той же результат, що і setinterval. Питання полягало у виконанні цих двох варіантів.
Томаш Гонсалес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.