setTimeout oder setInterval?

763

Soweit ich das beurteilen kann, verhalten sich diese beiden Javascript-Teile gleich:

Option A:

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

myTimeoutFunction();

Option B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

Gibt es einen Unterschied zwischen der Verwendung von setTimeout und setInterval ?

Damovisa
quelle
6
Wenn Sie einige gute Details zur Funktionsweise von Timern in JS wünschen, hat John Resig einen guten Artikel zu diesem Thema geschrieben
Rafael
9
Es gibt auch den offensichtlichen Unterschied, dass setTimeout diese zusätzliche Codezeile benötigt, um die Weitergabe aufrechtzuerhalten. Dies hat den Nachteil, dass es sich um ein Wartungsproblem handelt, aber den Vorteil, dass Sie den Zeitraum leicht ändern können
annakata
Versuchen Sie dies jsfiddle.net/pramendra/Y4vEV
Pramendra Gupta
4
Danke @JapanPro, aber ich hatte nie wirklich Probleme, Timeouts zum Laufen zu bringen. In diesem Beitrag ging es darum, was der Unterschied war und was verwendet werden sollte.
Damovisa

Antworten:

670

Sie versuchen im Wesentlichen, dasselbe zu tun, aber der setIntervalAnsatz ist genauer als der setTimeoutAnsatz, da setTimeout1000 ms gewartet, die Funktion ausgeführt und dann eine weitere Zeitüberschreitung festgelegt wird. Die Wartezeit beträgt also etwas mehr als 1000 ms (oder viel mehr, wenn die Ausführung Ihrer Funktion lange dauert).

Obwohl man denken könnte, setIntervalwird ausgeführt , genau alle 1000 ms, ist es wichtig zu beachten , dass setIntervalauch verzögern, da JavaScript nicht eine Multi-Threaded - Sprache ist, was bedeutet , dass - wenn es andere Teile des Skripts ausgeführt wird - das Intervall hat darauf warten, dass das zu Ende ist.

In dieser Geige können Sie deutlich sehen, dass das Zeitlimit zurückfällt, während das Intervall fast immer bei fast 1 Aufruf / Sekunde liegt (was das Skript versucht). Wenn Sie die Geschwindigkeitsvariable oben auf etwas Kleines wie 20 ändern (was bedeutet, dass versucht wird, 50 Mal pro Sekunde zu laufen), erreicht das Intervall nie ganz durchschnittlich 50 Iterationen pro Sekunde.

Die Verzögerung ist fast immer vernachlässigbar, aber wenn Sie etwas wirklich Genaues programmieren, sollten Sie sich für einen selbsteinstellenden Timer entscheiden (der im Wesentlichen ein Timeout-basierter Timer ist, der sich ständig an die Verzögerung anpasst, die er erzeugt).

David Snabel-Caunt
quelle
4
Andy hatte einen ähnlichen Vorschlag. Bedeutet dies hypothetisch, dass, wenn die Ausführung der Methode mehr als 1000 ms dauert, mehrere gleichzeitig ausgeführt werden können?
Damovisa
14
Theoretisch ja. In der Praxis nein, da Javascript Multithreading nicht unterstützt. Wenn Ihr Code länger als 1000 ms dauert, wird der Browser eingefroren.
Kamiel Wanrooij
61
Technisch gesehen wird der Code nicht genau alle 1000 ms ausgeführt, da dies von der Auflösung des Timers abhängt und davon, ob bereits anderer Code ausgeführt wird. Ihr Punkt steht aber immer noch.
Matthew Crumley
10
setInterval unterscheidet sich in zweierlei Hinsicht: 1. setInterval ist nicht rekursiv und setInterval ruft Ihre Funktion zum ersten Mal nach der angegebenen Zeit auf, während setTimeout zum ersten Mal ohne Verzögerung aufgerufen wird. Danach wird es nach der angegebenen Zeit erneut aufgerufen. Nach der ersten Ausführung funktionieren sie fast gleich.
Hafiz
5
Der Unterschied besteht darin, dass sich setTimeout nicht wiederholt. Sie können ein Skript nach einer festgelegten Zeit ausführen, jedoch nur einmal. Das setInterval hingegen wiederholt dieses Skript, bis es mit clearTimeout () gestoppt wird.
Leander
648

Gibt es einen Unterschied?

Ja. Ein Timeout führt eine bestimmte Zeitspanne aus, nachdem setTimeout () aufgerufen wurde. Ein Intervall wird eine bestimmte Zeitspanne nach dem Auslösen des vorherigen Intervalls ausgeführt.

Sie werden den Unterschied bemerken, wenn die Ausführung Ihrer doStuff () -Funktion eine Weile dauert. Wenn wir beispielsweise einen Aufruf von setTimeout / setInterval mit ., ein Auslösen des Timeouts / Intervalls mit *und die Ausführung von JavaScript-Code mit darstellen [-----], sehen die Zeitleisten wie folgt aus:

Timeout:

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

Interval:

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

Die nächste Komplikation besteht darin, dass ein Intervall ausgelöst wird, während JavaScript bereits beschäftigt ist (z. B. die Behandlung eines vorherigen Intervalls). In diesem Fall wird das Intervall gespeichert und erfolgt, sobald der vorherige Handler beendet ist und die Steuerung an den Browser zurückgibt. So zum Beispiel für einen doStuff () -Prozess, der manchmal kurz ([-]) und manchmal lang ([-----]) ist:

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

• stellt ein Intervallfeuer dar, das seinen Code nicht sofort ausführen konnte und stattdessen ausstehend gemacht wurde.

Intervalle versuchen also, aufzuholen, um wieder im Zeitplan zu sein. Sie stellen jedoch keine übereinander in die Warteschlange: Pro Intervall kann immer nur eine Ausführung anstehen. (Wenn sie alle in der Warteschlange stehen würden, würde der Browser eine ständig wachsende Liste ausstehender Ausführungen haben!)

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

x steht für ein Intervallfeuer, das nicht ausgeführt oder ausstehend gemacht werden konnte und stattdessen verworfen wurde.

Wenn die Ausführung Ihrer doStuff () -Funktion gewöhnlich länger dauert als das dafür festgelegte Intervall, verbraucht der Browser 100% der CPU, die versucht, sie zu warten, und reagiert möglicherweise weniger schnell.

Welches benutzt du und warum?

Chained-Timeout bietet dem Browser eine garantierte freie Zeit. Intervall versucht sicherzustellen, dass die von ihm ausgeführte Funktion auf Kosten der Verfügbarkeit der Browser-Benutzeroberfläche so nahe wie möglich an den geplanten Zeiten ausgeführt wird.

Ich würde ein Intervall für einmalige Animationen in Betracht ziehen, das ich so flüssig wie möglich gestalten wollte, während verkettete Zeitüberschreitungen für laufende Animationen, die während des Ladens der Seite ständig stattfinden, höflicher sind. Für weniger anspruchsvolle Anwendungen (z. B. ein trivialer Updater, der alle 30 Sekunden ausgelöst wird oder so), können Sie beide sicher verwenden.

In Bezug auf die Browserkompatibilität ist setTimeout älter als setInterval, aber alle Browser, die Sie heute treffen, unterstützen beide. Der letzte Streuner seit vielen Jahren war IE Mobile in WinMo <6.5, aber hoffentlich liegt auch das jetzt hinter uns.

Bobince
quelle
Aber gilt der Grund für die Wahl zwischen Intervall und Timeout auch für Nicht-Browser-Plattformen wie WebOS oder JIL?
Vid L
2
Eine gute Möglichkeit, verkettete Timeouts für anonyme Funktionen durchzuführen: setTimeout (function () {setTimeout (argument.callee, 10)}, 10)
Justin Meyer
1
In Bezug auf die Browserkompatibilität bieten alle Browser zwar beide Methoden, ihre Leistung ist jedoch unterschiedlich.
Unigg
"Aber dann ist es wahrscheinlich, dass es auch nichts anderes unterstützt, was Sie verwenden", also sehr wahr
Basic
1
Drum Machine von Chrom Project mit setTimeout ("Schedule ()", 0); Der Browser verfügt also nicht über unnötige Stapel, wenn es sich um eine Hintergrundregisterkarte für Chrome oder mangelnde Ressourcen handelt.
Elliot Yap
91

setInterval ()

setInterval()ist eine zeitintervallbasierte Codeausführungsmethode, die die native Fähigkeit besitzt, ein angegebenes Skript wiederholt auszuführen, wenn das Intervall erreicht ist. Es sollte vom Skriptautor nicht in seine Rückruffunktion verschachtelt werden, damit es eine Schleife ausführt, da es standardmäßig eine Schleife ausführt . Es wird in der Pause weiter ausgelöst, es sei denn, Sie rufen an clearInterval().

Wenn Sie Code für Animationen oder auf einem Uhr-Tick schleifen möchten, verwenden Sie setInterval().

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

setTimeout ()

setTimeout()ist eine zeitbasierte Codeausführungsmethode, die ein Skript nur einmal ausführt, wenn das Intervall erreicht ist. Es wird nicht erneut wiederholt, es sei denn, Sie richten es so aus, dass es das Skript schleift, indem Sie das setTimeout()Objekt in die Funktion verschachteln, die es zum Ausführen aufruft. Wenn es auf Schleife eingestellt ist, wird es in der Pause weiter abgefeuert, es sei denn, Sie rufen an clearTimeout().

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

Wenn Sie möchten, dass nach einem bestimmten Zeitraum einmal etwas passiert, verwenden Sie setTimeout(). Dies liegt daran, dass es nur einmal ausgeführt wird, wenn das angegebene Intervall erreicht ist.

Haris
quelle
6
Schöne Erklärung, aber beachten Sie, dass das OP den grundlegenden Unterschied in den vom OP bereitgestellten Beispielen versteht. Beachten Sie insbesondere, dass im setTimeout()Beispiel des OP rekursivsetTimeout() aufgerufen wird , während dies nicht der Fall ist. setInterval()
DavidRR
44

Das setInterval erleichtert das Abbrechen der zukünftigen Ausführung Ihres Codes. Wenn Sie setTimeout verwenden, müssen Sie die Timer-ID verfolgen, falls Sie sie später abbrechen möchten.

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

myTimeoutFunction();

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

gegen

function myTimeoutFunction()
{
    doStuff();
}

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

// later on...
clearInterval(timerId);
Kamiel Wanrooij
quelle
35
Ich sehe nicht, wie Sie im Fall von setInterval die Timer-ID nicht verfolgen. Es ist nur aus der Funktion herausgezogen.
Kekoa
1
Eine andere Option setTimeoutist, anstatt die ID zu speichern, eine ifAnweisung hinzuzufügen , um das nächste Zeitlimit nur festzulegen, wenn eine Bedingung erfüllt ist.
nnnnnn
7
Kekoa, guter Punkt. Sie müssen die Intervall-ID jedoch nur einmal speichern. Die Timeout-ID ändert sich wahrscheinlich mit jedem Aufruf, sodass Sie diese Änderungen verfolgen müssen . Code, der das Timeout löschen möchte, muss irgendwie Zugriff auf den aktuellen Wert dieser Variablen haben. Außerdem kann das Zeitlimit während der Ausführung nicht gelöscht werden, doStuffda die ID ungültig ist. Es ist jedoch nicht wirklich notwendig, Timeout-IDs zu speichern. Stattdessen können Sie einfach aufhören zu telefonieren setTimeout.
Robert
4
Nach meiner Erfahrung möchten Sie die meiste Zeit auch mit setTimeout abbrechen können. 99% der Zeit, die Sie abbrechen möchten, bevor der nächste Aufruf erfolgt, nicht nachdem der nächste abgeschlossen ist.
Kamiel Wanrooij
23

Ich finde die setTimeoutMethode einfacher zu verwenden, wenn Sie das Timeout abbrechen möchten:

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

myTimeoutFunction();

Wenn in der Funktion etwas schief gehen würde, wird der Fehler beim ersten Mal nicht mehr wiederholt, anstatt den Fehler jede Sekunde zu wiederholen.

Guffa
quelle
20

Der Unterschied liegt in ihren Zwecken.

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

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

So einfach ist das

Weitere Details finden Sie hier http://javascript.info/tutorial/settimeout-setinterval

kmario23
quelle
7
Schöne, prägnante Erklärung, aber beachten Sie, dass das OP den grundlegenden Unterschied in den vom OP bereitgestellten Beispielen versteht. Beachten Sie insbesondere, dass im setTimeout()Beispiel des OP rekursivsetTimeout() aufgerufen wird , während dies nicht der Fall ist. setInterval()
DavidRR
14

Wenn Sie eine Funktion in setInterval ausführen, die länger als das Timeout funktioniert, bleibt der Browser hängen.

- Zum Beispiel dauert doStuff () 1500 Sekunden. ausgeführt werden und Sie tun: setInterval (doStuff, 1000);
1) Führen Sie doStuff ( ) im Browser aus, was 1,5 Sekunden dauert. ermordet werden;
2) Nach ~ 1 Sekunde wird versucht, doStuff () erneut auszuführen . Das vorherige doStuff () wird jedoch weiterhin ausgeführt->, sodass der Browser diesen Lauf zur Warteschlange hinzufügt (um ausgeführt zu werden, nachdem der erste ausgeführt wurde).
3,4, ..) Das gleiche Hinzufügen zur Ausführungswarteschlange für die nächsten Iterationen, aber doStuff () von vorherigen sind noch in Bearbeitung ...
Infolgedessen bleibt der Browser hängen.

Um dieses Verhalten zu verhindern, führen Sie setTimeout am besten in setTimeout aus, um setInterval zu emulieren .
Um Zeitüberschreitungen zwischen setTimeout-Aufrufen zu korrigieren, können Sie eine selbstkorrigierende Alternative zur setInterval- Technik von JavaScript verwenden.

Serg Hospodarets
quelle
1
Ich weiß nicht, warum niemand in dieser Antwort einen Wert gefunden hat!
Randika Vishman
9

Ich benutze setTimeout.

Anscheinend besteht der Unterschied darin, dass setTimeout die Methode einmal aufruft, setInterval sie wiederholt aufruft.

Hier ist ein guter Artikel, der den Unterschied erklärt: Tutorial: JavaScript-Timer mit setTimeout und setInterval

Bravax
quelle
2
Ja, ich habe diesen Unterschied, aber die beiden Code-Teile, die ich bereitgestellt habe, sollten dann dasselbe tun ...
Damovisa
Ähm ja ... hätte ich gedacht ... aber laut dcaunt und seiner Stimmenzahl ist das nicht ganz das, was passiert.
Bravax
9

Ihr Code hat unterschiedliche Ausführungsintervalle, und in einigen Projekten, z. B. bei Online-Spielen, ist dies nicht akzeptabel. Was sollten Sie zuerst tun, damit Ihr Code mit denselben Intervallen funktioniert? Ändern Sie "myTimeoutFunction" wie folgt:

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

Nach dieser Änderung ist es gleich

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

Sie haben jedoch immer noch kein stabiles Ergebnis, da JS Single-Threaded ist. Wenn der JS-Thread mit etwas beschäftigt ist, kann er Ihre Rückruffunktion vorerst nicht ausführen, und die Ausführung wird um 2-3 ms verschoben. Haben Sie 60 Ausführungen pro Sekunde und jedes Mal, wenn Sie eine zufällige Verzögerung von 1-3 Sekunden haben, ist dies absolut nicht akzeptabel (nach einer Minute beträgt die Verzögerung etwa 7200 ms), und ich kann Ihnen raten, so etwas zu verwenden:

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

Dieser Code garantiert eine stabile Ausführungsdauer. Sogar der Thread ist beschäftigt und Ihr Code wird nach 1005 ms ausgeführt. Beim nächsten Mal tritt eine Zeitüberschreitung von 995 ms auf, und das Ergebnis ist stabil.

degr
quelle
7

Ich habe einen einfachen Test durchgeführt setInterval(func, milisec), weil ich neugierig war, was passiert, wenn der Funktionszeitverbrauch größer als die Intervalldauer ist.

setIntervalIn der Regel wird die nächste Iteration unmittelbar nach dem Start der vorherigen Iteration geplant, es sei denn, die Funktion wird noch ausgeführt . Wenn ja, setIntervalwarten Sie, bis die Funktion endet. Sobald dies geschieht, wird die Funktion sofort wieder ausgelöst - es wird nicht auf die nächste Iteration gemäß Zeitplan gewartet (wie dies unter Bedingungen ohne Zeitüberschreitung der Funktion der Fall wäre). Es gibt auch keine Situation, in der parallele Iterationen ausgeführt werden.

Ich habe dies auf Chrome v23 getestet. Ich hoffe, es ist eine deterministische Implementierung in allen modernen Browsern.

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

Konsolenausgabe:

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

Die waitFunktion ist nur ein Thread-Blocking-Helfer - ein synchroner Ajax-Aufruf, der auf der Serverseite genau 2500 Millisekunden verarbeitet:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
jwaliszko
quelle
1
"Keine Situation mit parallelen Iterationen" - ja, das sollte unmöglich sein. Clientseitiges JavaScript verfügt über ein einzelnes Thread-Ausführungsmodell, sodass nie gleichzeitig etwas passiert (Ereignishandler usw.). Aus diesem Grund passiert während des synchronen Ajax-Aufrufs nichts (und der Browser reagiert nicht).
MrWhite
Reagiert der Browser in den wenigen ms zwischen "Intervallen"? Würde ein anderes Ereignis ausgelöst, wenn es ansteht? (Danke für die Tests zwischen +1)
MrWhite
1
Laut MDN wird es als " gefährliche Verwendung " angesehen, wenn die Funktion länger als die Intervallzeit ausgeführt werden könnte. Ein rekursiver setTimoutAufruf wird bevorzugt.
MrWhite
6

Um es etwas anders zu betrachten: setInterval stellt sicher, dass ein Code in jedem Intervall ausgeführt wird (dh 1000 ms oder wie viel Sie angeben), während setTimeout die Zeit festlegt, die es wartet, bis der Code ausgeführt wird. Da die Ausführung des Codes zusätzliche Millisekunden dauert, summiert sich der Wert auf 1000 ms, sodass setTimeout zu ungenauen Zeiten (über 1000 ms) erneut ausgeführt wird.

Zum Beispiel werden Timer / Countdowns nicht mit setTimeout ausgeführt, sondern mit setInterval, um sicherzustellen, dass es nicht verzögert wird und der Code im genau angegebenen Intervall ausgeführt wird.

CatalinBerta
quelle
5

Sowohl setInterval als auch setTimeout geben eine Timer-ID zurück, mit der Sie die Ausführung abbrechen können, dh bevor die Zeitüberschreitungen ausgelöst werden. Um abzubrechen, rufen Sie entweder clearInterval oder clearTimeout wie folgt auf:

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

Außerdem werden die Zeitüberschreitungen automatisch abgebrochen, wenn Sie die Seite verlassen oder das Browserfenster schließen.

Helgi
quelle
4

Sie können die Bobince-Antwort selbst validieren, wenn Sie das folgende Javascript ausführen oder diese JSFiddle überprüfen

<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);
});
Gudradain
quelle
3

Nun, setTimeout ist in einer Situation besser, wie ich gerade gelernt habe. Ich benutze immer setInterval, das ich länger als eine halbe Stunde im Hintergrund laufen lassen muss. Als ich zu dieser Registerkarte zurückkehrte, änderte sich die Diashow (auf der der Code verwendet wurde) sehr schnell, anstatt alle 5 Sekunden, die sie haben sollte. Es passiert tatsächlich wieder, wenn ich es mehr teste und es nicht wichtig ist, ob es der Fehler des Browsers ist oder nicht, denn mit setTimeout ist diese Situation völlig unmöglich.

Nino
quelle
Klingt so, als hätten Sie setInterval in der von Ihnen aufgerufenen Funktion aufgerufen. So schleifen Sie mit setTimeout, aber mit setInterval erstellen Sie bei jedem Aufruf eine völlig neue Schleife.
Stephen R
2

Der Unterschied ist in der Konsole offensichtlich:

Geben Sie hier die Bildbeschreibung ein

testCoder
quelle
2

Wenn Sie nur das hinzufügen, was bereits gesagt wurde, aber die setTimeout-Version des Codes auch das erreicht Maximum call stack size, wird es nicht mehr funktionieren. Da es keinen Basisfall gibt, bei dem die rekursive Funktion anhalten kann, kann sie nicht für immer ausgeführt werden.

Maaz
quelle
Ich denke nicht, dass das wahr ist. Siehe hier stackoverflow.com/questions/8058612/…
Kevin Wheeler
-1

Der allgemeinste Unterschied zwischen und setInterval (Ausdruck, Dauer) ist der folgende

setTimeout () führt den Ausdruck nur EINMAL und nach dieser angegebenen Dauer aus.

Jedoch,

setInterval () führt den Ausdruck in der INFINITE-LOOP nach jeder angegebenen Dauer aus.

Anshu Aditya
quelle
-5

Ich denke SetIntervalund bin SetTimeoutanders. SetIntervalführt den Block gemäß der eingestellten Zeit aus, während SetTimeoutder Codeblock einmal ausgeführt wird.

Probieren Sie diese Codes nach den Countdown-Sekunden für das Timeout aus:

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

und dann versuchen

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

Sie können die Unterschiede selbst sehen.

Ugbana Chukwujindu Kelvin
quelle
Dies beantwortet die Frage nicht. Settimeout () kann rekursiv verwendet werden, um das gleiche Ergebnis wie setinterval zu erhalten. Die Frage betraf die Leistung dieser beiden Optionen.
Tomas Gonzalez