setTimeout czy setInterval?


763

O ile wiem, te dwa elementy javascript zachowują się w ten sam sposób:

Opcja A:

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

myTimeoutFunction();

Opcja B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Czy jest jakaś różnica między użyciem setTimeout i setInterval ?


6
Jeśli chciałbyś uzyskać kilka dobrych szczegółów na temat działania timerów w JS, John Resig napisał dobry artykuł na ten temat
Rafael

9
istnieje również oczywistą różnicą, że setTimeout wymaga tego dodatkowego wiersza kodu, aby go rozmnożeniowego, który ma tę wadę, że jest to problem utrzymanie ale zaletą pozwalając łatwo zmienić okres
annakata


4
Dzięki @JapanPro, ale tak naprawdę nigdy nie miałem problemu z uruchomieniem limitów czasu. Ten post był o tym, jaka była różnica i które należy wykorzystać.
Damovisa,

Odpowiedzi:


670

Zasadniczo próbują zrobić to samo, ale setIntervalpodejście będzie dokładniejsze niż setTimeoutpodejście, ponieważ setTimeoutczeka 1000 ms, uruchamia funkcję, a następnie ustawia inny limit czasu. Tak więc okres oczekiwania wynosi w rzeczywistości nieco ponad 1000 ms (lub o wiele więcej, jeśli wykonanie funkcji zajmuje dużo czasu).

Chociaż można by pomyśleć, że setIntervalbędzie wykonywany dokładnie co 1000 ms, należy zauważyć, że setIntervalrównież się opóźni, ponieważ JavaScript nie jest językiem wielowątkowym, co oznacza, że ​​- jeśli działają inne części skryptu - interwał będzie miał czekać, aż to się skończy.

W tym skrzypce wyraźnie widać, że limit czasu się opóźnia, podczas gdy interwał jest prawie cały czas przy prawie 1 wywołaniu na sekundę (co skrypt próbuje zrobić). Jeśli zmienisz zmienną prędkości u góry na coś małego, na przykład 20 (co oznacza, że ​​będzie próbowała działać 50 razy na sekundę), przedział nigdy nie osiągnie średnio 50 iteracji na sekundę.

Opóźnienie jest prawie zawsze nieistotne, ale jeśli programujesz coś naprawdę precyzyjnego, powinieneś wybrać samoregulujący się licznik czasu (który w zasadzie jest licznikiem czasu, który stale dostosowuje się do tworzonego opóźnienia)


4
Andy miał podobną sugestię. Hipotetycznie, czy to oznacza, że ​​jeśli wykonanie metody zajmuje więcej niż 1000 ms, możesz mieć uruchomionych więcej niż jeden jednocześnie?
Damovisa,

14
Teoretycznie tak. W praktyce nie, ponieważ JavaScript nie obsługuje wielowątkowości. Jeśli Twój kod zajmie więcej niż 1000 ms, zawiesi przeglądarkę.
Kamiel Wanrooij,

61
Technicznie kod nie będzie wykonywany dokładnie co 1000 ms, ponieważ zależy to od rozdzielczości timera i od tego, czy inny kod jest już wykonywany. Twój punkt jest jednak nadal ważny.
Matthew Crumley,

10
setInterval różni się na dwa sposoby: 1. setInterval nie jest rekurencyjny, a setInterval po raz pierwszy wywoła twoją funkcję po wskazanym czasie, a setTimeout po raz pierwszy zostanie wywołany bez opóźnień, a następnie zadzwoni ponownie po tym czasie. Po pierwszym wykonaniu działają prawie tak samo.
Hafiz

5
Różnica polega na tym, że setTimeout się nie powtarza. Pozwala uruchomić skrypt po określonym czasie, ale tylko raz. Z drugiej strony setInterval będzie powtarzał ten skrypt, dopóki nie zostanie zatrzymany za pomocą clearTimeout ().
Leander

648

Czy jest jakaś różnica?

Tak. Limit czasu jest wykonywany przez określony czas po wywołaniu setTimeout (); Interwał wykonuje określony czas po wystrzeleniu poprzedniego interwału.

Zauważysz różnicę, jeśli wykonanie funkcji doStuff () zajmie trochę czasu. Na przykład, jeśli reprezentujemy wywołanie setTimeout / setInterval za pomocą ., uruchomienie limitu czasu / interwału *i wykonanie kodu JavaScript za pomocą [-----], linie czasu wyglądają następująco:

Timeout:

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

Interval:

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

Następną komplikacją jest sytuacja, gdy interwał jest uruchamiany, gdy JavaScript jest już zajęty robieniem czegoś (np. Obsługą poprzedniego interwału). W takim przypadku interwał zostanie zapamiętany i nastąpi natychmiast po zakończeniu poprzedniej procedury obsługi i zwróceniu kontroli do przeglądarki. Na przykład dla procesu doStuff (), który jest czasami krótki ([-]), a czasem długi ([-----]):

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

• reprezentuje odpalanie interwału, które nie mogło od razu wykonać swojego kodu, a zamiast tego zostało oczekujące.

Interwały próbują więc „nadrobić zaległości”, aby wrócić do harmonogramu. Ale nie ustawiają się w kolejce jeden po drugim: na interwał może być tylko jedno wykonanie. (Gdyby wszystkie stały w kolejce, przeglądarka miałaby ciągle powiększającą się listę zaległych wykonań!)

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

x oznacza odpalenie interwału, które nie mogło zostać wykonane lub być w toku, dlatego zostało odrzucone.

Jeśli funkcja doStuff () zwykle trwa dłużej niż ustawiony dla niej interwał, przeglądarka zje 100% procesora próbującego ją obsłużyć i może stać się mniej wrażliwa.

Z którego korzystasz i dlaczego?

Chained-Timeout zapewnia przeglądarce wolne miejsce w wolnym czasie; Interwał stara się zapewnić, aby działająca funkcja była wykonywana jak najbliżej zaplanowanych godzin, kosztem dostępności interfejsu użytkownika przeglądarki.

Zastanawiałbym się, czy interwał jednorazowych animacji powinien być jak najbardziej płynny, podczas gdy przerwy w łańcuchach są bardziej grzeczne w przypadku trwających animacji, które miałyby miejsce przez cały czas podczas ładowania strony. W przypadku mniej wymagających zastosowań (takich jak trywialne odpalanie aktualizacji co 30 sekund lub coś w tym rodzaju) możesz bezpiecznie użyć jednego z nich.

Pod względem zgodności z przeglądarkami setTimeout poprzedza setInterval, ale wszystkie przeglądarki, które spotkasz dzisiaj, obsługują oba. Ostatnim maruderem od wielu lat była IE Mobile w WinMo <6,5, ale mam nadzieję, że to też jest już za nami.


Ale czy powód wyboru między Interwałem a Limitem czasu dotyczy nawet platform innych niż przeglądarki, takich jak na przykład WebOS lub JIL?
Vid L,

2
Fajny sposób wykonywania połączonych limitów czasu dla funkcji anonimowych: setTimeout (function () {setTimeout (arguments.callee, 10)}, 10)
Justin Meyer

1
Pod względem kompatybilności przeglądarki, chociaż wszystkie przeglądarki zapewniają obie metody, ich wydajność jest inna.
unigg

„Ale są szanse, że nie obsługuje niczego innego, z czego korzystasz”, więc bardzo prawdziwa
Basic

1
automat perkusyjny według projektu chromu przy użyciu setTimeout („schedule ()”, 0); Tak więc przeglądarka nie będzie miała niepotrzebnego stosu, gdy jest zakładką w tle dla chrome lub braku zasobów.
Elliot Yap

90

setInterval ()

setInterval()jest metodą wykonania kodu opartą na interwałach czasowych, która ma natywną zdolność do wielokrotnego uruchamiania określonego skryptu po osiągnięciu tego interwału. To powinno nie być zagnieżdżone w jego funkcji zwrotnej przez autora skryptu, aby to pętla, ponieważ pętle domyślnie . Będzie strzelał z przerwą, chyba że zadzwonisz clearInterval().

Jeśli chcesz zapętlić kod animacji lub zaznaczyć takt zegara, użyj setInterval().

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

setTimeout ()

setTimeout()to metoda wykonania kodu oparta na czasie, która wykona skrypt tylko jeden raz, gdy zostanie osiągnięty interwał. Będzie nie powtórzyć jeszcze raz, jeśli nie dostosować go do pętli skryptu przez zagnieżdżanie się setTimeout()wewnątrz obiektu funkcji wywołuje uruchomić. Jeśli jest nastawiony na pętlę, będzie strzelał z przerwą, chyba że zadzwonisz clearTimeout().

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

Jeśli chcesz, aby coś się wydarzyło po upływie określonego czasu, użyj setTimeout(). Wynika to z tego, że wykonuje się tylko jeden raz po osiągnięciu określonego przedziału czasu.


6
Dobre wyjaśnienie, ale zauważ, że PO rozumie podstawową różnicę w podanych przykładach PO. W szczególności należy zauważyć, że w setTimeout()przykładzie PO setTimeout()jest wywoływany rekurencyjnie , podczas gdy setInterval()nie jest.
DavidRR

44

SetInterval ułatwia anulowanie przyszłego wykonania kodu. Jeśli używasz setTimeout, musisz śledzić identyfikator timera na wypadek, gdybyś chciał go później anulować.

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

myTimeoutFunction();

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

przeciw

function myTimeoutFunction()
{
    doStuff();
}

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

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

35
Nie widzę, jak nie śledzisz identyfikatora timera w przypadku setInterval. Właśnie został wyciągnięty z funkcji.
Kekoa

1
Inną opcją setTimeoutjest raczej niż zapisywanie id add ifinstrukcji, aby ustawić następny limit czasu tylko wtedy, gdy jakiś warunek jest spełniony.
nnnnnn

7
Kekoa, dobra uwaga. Ale musisz zapisać identyfikator interwału tylko raz. Identyfikator limitu czasu prawdopodobnie zmienia się przy każdym wywołaniu, więc musisz śledzić te zmiany. Kod, który chce skasować limit czasu, musi jakoś mieć dostęp do bieżącej wartości tej zmiennej. Ponadto nie można wyczyścić limitu czasu podczas działania, doStuffponieważ identyfikator jest nieprawidłowy. Jednak tak naprawdę nie jest konieczne zapisywanie identyfikatorów przekroczenia limitu czasu. Zamiast tego możesz po prostu przestać dzwonić setTimeout.
Robert

4
Z mojego doświadczenia wynika, że ​​większość czasu chcesz móc anulować nawet podczas korzystania z setTimeout. 99% czasu, który chcesz anulować, zanim nastąpi kolejne wywołanie, a nie po zakończeniu następnego.
Kamiel Wanrooij,

23

Uważam, że setTimeoutmetoda jest łatwiejsza w użyciu, jeśli chcesz anulować limit czasu:

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

myTimeoutFunction();

Ponadto, jeśli coś pójdzie nie tak w funkcji, przestanie się powtarzać przy pierwszym błędzie, zamiast powtarzać błąd co sekundę.


20

Różnica tkwi w ich celach.

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

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

To takie proste

Więcej szczegółowych informacji tutaj http://javascript.info/tutorial/settimeout-setinterval


7
Ładne, zwięzłe wyjaśnienie, ale zauważ, że PO rozumie podstawową różnicę w podanych przykładach PO. W szczególności należy zauważyć, że w setTimeout()przykładzie PO setTimeout()jest wywoływany rekurencyjnie , podczas gdy setInterval()nie jest.
DavidRR

14

Kiedy uruchomisz jakąś funkcję w setInterval, która działa dłużej niż limit czasu-> przeglądarka utknie.

- Np. DoStuff () zajmuje 1500 sekund. wykonać, a ty zrobisz: setInterval (doStuff, 1000);
1) Uruchom przeglądarkę doStuff (), co zajmuje 1,5 sekundy. być straconym;
2) Po ~ 1 sekundzie próbuje ponownie uruchomić doStuff () . Ale poprzednia funkcja doStuff () jest nadal wykonywana-> więc przeglądarka dodaje to uruchomienie do kolejki (uruchamiane po wykonaniu pierwszej).
3,4, ..) To samo dodawanie do kolejki wykonywania dla następnych iteracji, ale doStuff () z poprzednich jest nadal w toku ...
W rezultacie przeglądarka utknęła.

Aby temu zapobiec, najlepszym sposobem jest uruchomienie setTimeout wewnątrz setTimeout w celu emulacji setInterval .
Aby skorygować limity czasu między wywołaniami setTimeout, można użyć samokorekty jako alternatywy dla techniki setInterval JavaScript .


1
Nie wiem, dlaczego nikt nie znalazł żadnej wartości w tej odpowiedzi!
Randika Vishman


9

Twój kod będzie miał różne przedziały czasowe wykonywania, a w niektórych projektach, takich jak gry online, jest to niedopuszczalne. Po pierwsze, co należy zrobić, aby kod działał z tymi samymi przedziałami, należy zmienić „myTimeoutFunction” na:

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

Po tej zmianie będzie ona równa

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

Ale nadal nie będziesz mieć stabilnego wyniku, ponieważ JS jest jednowątkowy. Na razie, jeśli wątek JS będzie zajęty czymś, nie będzie mógł wykonać funkcji wywołania zwrotnego, a wykonanie zostanie odroczone o 2-3 ms. Czy masz 60 egzekucji na sekundę i za każdym razem, gdy masz losowe opóźnienie 1-3 sekund, będzie to absolutnie niedopuszczalne (po jednej minucie będzie to około 7200 ms) i mogę doradzić, aby użyć czegoś takiego:

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

Ten kod gwarantuje stabilny okres realizacji. Nawet wątek będzie zajęty, a Twój kod zostanie wykonany po 1005 ms, następnym razem będzie miał limit czasu na 995 ms, a wynik będzie stabilny.


7

Zrobiłem prosty test setInterval(func, milisec) , ponieważ byłem ciekawy, co się dzieje, gdy zużycie czasu funkcji jest większe niż czas interwału.

setIntervalbędzie ogólnie zaplanować następną iterację tuż po starcie poprzedniej iteracji, chyba że funkcja ta jest nadal w toku . Jeśli tak, setIntervalzaczeka, aż funkcja się skończy. Jak tylko to się stanie, funkcja jest natychmiast ponownie uruchamiana - nie trzeba czekać na następną iterację zgodnie z harmonogramem (tak jak byłoby w warunkach bez funkcji przekroczenia czasu). Nie ma również sytuacji z uruchomionymi równoległymi iteracjami.

Przetestowałem to na Chrome v23. Mam nadzieję, że jest to deterministyczne wdrożenie we wszystkich nowoczesnych przeglądarkach.

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

Dane wyjściowe konsoli:

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

Ta waitfunkcja jest tylko pomocnikiem do blokowania wątków - synchroniczne wywołanie ajax, które zajmuje dokładnie 2500 milisekund przetwarzania po stronie serwera:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}

1
„brak sytuacji z uruchomionymi równoległymi iteracjami” - tak, powinno to być niemożliwe. JavaScript po stronie klienta ma jednowątkowy model wykonania, więc nic (procedury obsługi zdarzeń itp.) Nigdy się nie dzieje w tym samym czasie. Dlatego nic się nie dzieje (a przeglądarka nie odpowiada) podczas synchronicznego wywołania ajax.
MrWhite

Czy przeglądarka reaguje w ciągu kilku ms między „interwałami”? Czy inne wydarzenie zadziała, jeśli jest w toku? (Dzięki za testy btw +1)
MrWhite

1
Według MDN uważa się za „ niebezpieczne użycie ”, jeśli funkcja może działać dłużej niż czas przerwy. setTimoutPreferowane jest połączenie rekurencyjne .
MrWhite,

6

Aby spojrzeć na to trochę inaczej: setInterval zapewnia, że ​​kod jest uruchamiany w każdym podanym przedziale czasu (tj. 1000 ms lub ile określasz), podczas gdy setTimeout ustawia czas, w którym „czeka” do uruchomienia kodu. A ponieważ uruchomienie kodu zajmuje dodatkowe milisekundy, sumuje się do 1000 ms, a zatem setTimeout uruchamia się ponownie w niedokładnych czasach (ponad 1000 ms).

Na przykład liczniki czasu / odliczanie nie są wykonywane za pomocą setTimeout, są one wykonywane za pomocą setInterval, aby upewnić się, że nie opóźnia się, a kod działa dokładnie w danym interwale.


5

Zarówno setInterval, jak i setTimeout zwracają identyfikator timera, którego można użyć do anulowania wykonania, to znaczy przed uruchomieniem limitów czasu. Aby anulować, zadzwoń do clearInterval lub clearTimeout w następujący sposób:

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

Ponadto limity czasu są automatycznie anulowane po opuszczeniu strony lub zamknięciu okna przeglądarki.


4

Możesz samodzielnie sprawdzić poprawność odpowiedzi bobince po uruchomieniu następującego javascript lub sprawdzeniu tego 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

Cóż, setTimeout jest lepszy w jednej sytuacji, jak właśnie się dowiedziałem. Zawsze używam setInterval, który pozostawiłem w tle na ponad pół godziny. Kiedy wróciłem do tej zakładki, pokaz slajdów (na którym użyto kodu) zmieniał się bardzo szybko, zamiast co 5 sekund, które powinien mieć. W rzeczywistości zdarza się to ponownie, gdy testuję go bardziej i czy to wina przeglądarki, czy nie, nie jest to ważne, ponieważ dzięki setTimeout sytuacja jest całkowicie niemożliwa.


Brzmi tak, jakbyś wywołał setInterval w wywołanej funkcji. W ten sposób zapętlasz za pomocą setTimeout, ale dzięki setInterval tworzysz zupełnie nową pętlę za każdym razem, gdy jest wywoływana.
Stephen R


2

Po prostu dodając do tego, co już zostało powiedziane, ale wersja kodu setTimeout osiągnie również ten, Maximum call stack sizektóry zatrzyma jego działanie. Ponieważ nie ma podstawowego przypadku, w którym funkcja rekurencyjna mogłaby się zatrzymać, więc nie można jej uruchamiać na zawsze.


Nie sądzę, że to prawda. Zobacz tutaj stackoverflow.com/questions/8058612/…
Kevin Wheeler,

-1

Najbardziej ogólna różnica między i setInterval (wyrażenie, czas trwania) jest taka

setTimeout () wykona wyrażenie tylko RAZ i po upływie określonego czasu.

Jednak,

setInterval () wykona wyrażenie w INFINITE-LOOP po każdym określonym czasie trwania.


-5

Myślę SetIntervali SetTimeoutsą inne. SetIntervalwykonuje blok zgodnie z ustawionym czasem, SetTimeoutwykonuje blok kodu raz.

Wypróbuj następujący zestaw kodów po upływie sekund odliczania limitu czasu:

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

a następnie spróbuj

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

Różnice możesz zobaczyć dla siebie.


To nie odpowiada na pytanie. Funkcja settimeout () może być używana rekurencyjnie, aby dać taki sam wynik jak setinterval. Pytanie dotyczyło wydajności tych dwóch opcji.
Tomas Gonzalez
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.