Führen Sie die Funktion setInterval beim ersten Mal ohne Verzögerung aus

339

Es gibt eine Möglichkeit, die setIntervalMethode von Javascript so zu konfigurieren , dass die Methode sofort ausgeführt und dann mit dem Timer ausgeführt wird

Jorge
quelle
4
Nicht nativ. Sie können versuchen, das functioneinmal setInterval()
anzurufen

Antworten:

519

Es ist am einfachsten, die Funktion beim ersten Mal direkt selbst aufzurufen:

foo();
setInterval(foo, delay);

Es gibt jedoch gute Gründe, dies zu vermeiden setInterval- insbesondere unter bestimmten Umständen kann eine ganze Reihe von setIntervalEreignissen ohne Verzögerung unmittelbar nacheinander eintreffen. Ein weiterer Grund ist, dass Sie, wenn Sie die Schleife stoppen möchten, explizit aufrufen müssen, clearIntervalwas bedeutet, dass Sie sich an das vom ursprünglichen setIntervalAufruf zurückgegebene Handle erinnern müssen .

Eine alternative Methode besteht darin, foosich für nachfolgende Aufrufe auszulösen, indem Sie setTimeoutstattdessen Folgendes verwenden :

function foo() {
   // do stuff
   // ...

   // and schedule a repeat
   setTimeout(foo, delay);
}

// start the cycle
foo();

Dies garantiert, dass zwischen den Anrufen mindestens ein Intervall liegt delay. Es macht es auch einfacher, die Schleife bei Bedarf abzubrechen - Sie rufen nur nicht an, setTimeoutwenn Ihre Schleifenbeendigungsbedingung erreicht ist.

Besser noch, Sie können das alles in einem sofort aufgerufenen Funktionsausdruck zusammenfassen, der die Funktion erstellt, die sich dann wie oben wieder aufruft und automatisch die Schleife startet:

(function foo() {
    ...
    setTimeout(foo, delay);
})();

Dies definiert die Funktion und startet den Zyklus auf einmal.

Alnitak
quelle
5
Warum bevorzugst du setTimeout?
Sanghyun Lee
19
@Sangdol, weil es sicherstellt, dass Timer-Ereignisse nicht "gestapelt" werden, wenn sie nicht verarbeitet werden. Unter bestimmten Umständen kann eine ganze Reihe von setIntervalEreignissen ohne Verzögerung unmittelbar nacheinander eintreffen.
Alnitak
8
Es sollte eine Art Test geben, bei dem Sie nicht auf dem Stapel posten können, wenn Sie müde sind
James
3
Wie stoppe ich die Funktion, wenn ich die setTimeoutMethode verwende?
Gaurav Bhor
6
@ DaveMunger nein, weil es nicht wirklich rekursiv ist - es ist nur "pseudo-rekursiv". Die "rekursiven" Aufrufe erfolgen erst, wenn der Browser zur Ereignisschleife zurückkehrt. Zu diesem Zeitpunkt wurde der Aufrufstapel vollständig abgewickelt.
Alnitak
209

Ich bin mir nicht sicher, ob ich dich richtig verstehe, aber du könntest leicht so etwas tun:

setInterval(function hello() {
  console.log('world');
  return hello;
}(), 5000);

Es gibt offensichtlich eine Reihe von Möglichkeiten, dies zu tun, aber das ist die prägnanteste Art, die ich mir vorstellen kann.

chjj
quelle
16
Dies ist eine coole Antwort, da es sich um eine benannte Funktion handelt, die sofort ausgeführt wird und sich selbst zurückgibt. Genau das, wonach ich gesucht habe.
jmort253
41
Auf jeden Fall eine coole Lösung, die aber in Zukunft wahrscheinlich zu Verwirrung bei den Lesern führen wird.
Deepak Joy
4
Sie müssen ihm nicht den Namen "Hallo" geben. Sie könnten stattdessen argument.callee zurückgeben und dasselbe mit einer anonymen Funktion haben
JochenJung
10
@JochenJung arguments.calleeist nicht im strengen ES5-Modus verfügbar
Alnitak
3
Dies ist die Art von Javascript-Code, die die meisten neuen JS-Programmierer, die aus anderen Sprachen stammen, verwirren wird. Schreiben Sie eine Menge solcher Dinge, wenn Ihr Unternehmen nicht über viel JS-Personal verfügt und Sie Arbeitsplatzsicherheit wünschen.
Ian
13

Ich bin aufgrund des gleichen Problems auf diese Frage gestoßen, aber keine der Antworten hilft, wenn Sie sich genau so verhalten müssen,setInterval() aber mit dem einzigen Unterschied, dass die Funktion sofort am Anfang aufgerufen wird.

Hier ist meine Lösung für dieses Problem:

function setIntervalImmediately(func, interval) {
  func();
  return setInterval(func, interval);
}

Der Vorteil dieser Lösung:

  • vorhandener Code mit setIntervalkann einfach durch Ersetzen angepasst werden
  • arbeitet im strengen Modus
  • Es funktioniert mit vorhandenen benannten Funktionen und Abschlüssen
  • Sie können den Rückgabewert weiterhin verwenden und clearInterval()später weitergeben

Beispiel:

// create 1 second interval with immediate execution
var myInterval = setIntervalImmediately( _ => {
        console.log('hello');
    }, 1000);

// clear interval after 4.5 seconds
setTimeout( _ => {
        clearInterval(myInterval);
    }, 4500);

Um frech zu sein, wenn Sie wirklich brauchen, setIntervaldann können Sie auch das Original ersetzen setInterval. Daher ist keine Änderung des Codes erforderlich, wenn Sie diesen vor Ihrem vorhandenen Code hinzufügen:

var setIntervalOrig = setInterval;

setInterval = function(func, interval) {
    func();
    return setIntervalOrig(func, interval);
}

Alle oben aufgeführten Vorteile gelten hier, es ist jedoch keine Substitution erforderlich.

Jens Wirth
quelle
Ich bevorzuge diese Lösung gegenüber der setTimeoutLösung, da sie ein setIntervalObjekt zurückgibt . Um zu vermeiden, dass Funktionen aufgerufen werden, die möglicherweise später im Code enthalten sind und daher zum aktuellen Zeitpunkt nicht definiert sind, verpacke ich den ersten Funktionsaufruf in eine setTimeoutFunktion wie diese: setTimeout(function(){ func();},0);Die erste Funktion wird dann nach dem aktuellen Verarbeitungszyklus aufgerufen, der ebenfalls sofort erfolgt , dies aber ist mehr Fehler bewiesen.
Pensan
8

Sie können setInterval()eine Funktion einschließen , die dieses Verhalten bereitstellt:

function instantGratification( fn, delay ) {
    fn();
    setInterval( fn, delay );
}

... dann benutze es so:

instantGratification( function() {
    console.log( 'invoked' );
}, 3000);
user113716
quelle
5
Ich denke, Sie sollten zurückgeben, was setInterval zurückgibt. Dies liegt daran, dass Sie clearInterval ansonsten nicht verwenden können.
Henrik R
5

Hier ist ein Wrapper, um es hübsch zu machen, wenn Sie es brauchen:

(function() {
    var originalSetInterval = window.setInterval;

    window.setInterval = function(fn, delay, runImmediately) {
        if(runImmediately) fn();
        return originalSetInterval(fn, delay);
    };
})();

Setzen Sie das dritte Argument von setInterval auf true und es wird unmittelbar nach dem Aufruf von setInterval zum ersten Mal ausgeführt:

setInterval(function() { console.log("hello world"); }, 5000, true);

Oder lassen Sie das dritte Argument weg und es behält sein ursprüngliches Verhalten bei:

setInterval(function() { console.log("hello world"); }, 5000);

Einige Browser unterstützen zusätzliche Argumente für setInterval, die dieser Wrapper nicht berücksichtigt. Ich denke, diese werden selten verwendet, aber denken Sie daran, wenn Sie sie brauchen.

Mahn
quelle
9
Das Überschreiben nativer Browserfunktionen ist schrecklich, da es anderen koexistierenden Code beschädigen kann, wenn sich die Spezifikationen ändern. Tatsächlich hat setInterval derzeit mehr Parameter: developer.mozilla.org/en-US/docs/Web/API/WindowTimers/…
Áxel Costas Pena
2

Denn jemand muss das Äußere nach thisinnen bringen, als wäre es eine Pfeilfunktion.

(function f() {
    this.emit("...");
    setTimeout(f.bind(this), 1000);
}).bind(this)();

Wenn Sie der oben genannte Müll stört, können Sie stattdessen eine Schließung vornehmen.

(that => {
    (function f() {
        that.emit("...");
        setTimeout(f, 1000);
    })();
})(this);

Oder verwenden Sie den @autobindDekorator je nach Code.

Константин Ван
quelle
1

Ich werde vorschlagen, die Funktionen in der folgenden Reihenfolge aufzurufen

var _timer = setInterval(foo, delay, params);
foo(params)

Sie können das auch _timeran das foo weitergeben, wenn Sie clearInterval(_timer)unter einer bestimmten Bedingung möchten

var _timer = setInterval(function() { foo(_timer, params) }, delay);
foo(_timer, params);
Jayant Varshney
quelle
Könnten Sie dies genauer erklären?
Polyducks
Sie stellen den Timer ab dem zweiten Aufruf ein, zum ersten Mal rufen Sie einfach den fn direkt auf.
Jayant Varshney
1

Hier ist eine einfache Version für Anfänger, ohne herumzuspielen. Es deklariert nur die Funktion, ruft sie auf und startet dann das Intervall. Das ist es.

//Declare your function here
function My_Function(){
  console.log("foo");
}    

//Call the function first
My_Function();

//Set the interval
var interval = window.setInterval( My_Function, 500 );

Polyducks
quelle
1
Genau das macht die akzeptierte Antwort in den ersten Zeilen. Wie fügt diese Antwort etwas Neues hinzu?
Dan Dascalescu
In der akzeptierten Antwort heißt es weiter, dies nicht zu tun. Meine Antwort auf die akzeptierte Antwort erklärt, warum es immer noch eine gültige Methode ist. Das OP fordert ausdrücklich auf, die Funktion von setInterval beim ersten Aufruf aufzurufen, aber die akzeptierte Antwort wird umgeleitet, um über die Vorteile von setTimeout zu sprechen.
Polyducks
0

Um dieses Problem zu lösen, führe ich die Funktion ein erstes Mal aus, nachdem die Seite geladen wurde.

function foo(){ ... }

window.onload = function() {
   foo();
};

window.setInterval(function()
{
    foo(); 
}, 5000);
Dario
quelle
0

Es gibt ein praktisches npm-Paket namens firstInterval (vollständige Offenlegung, es ist meins).

Viele der Beispiele hier enthalten keine Parameterbehandlung, und das Ändern des Standardverhaltens setIntervalin einem großen Projekt ist böse. Aus den Dokumenten:

Dieses Muster

setInterval(callback, 1000, p1, p2);
callback(p1, p2);

ist identisch mit

firstInterval(callback, 1000, p1, p2);

Wenn Sie im Browser altmodisch sind und die Abhängigkeit nicht möchten, können Sie sie einfach aus dem Code ausschneiden und einfügen.

jimm101
quelle
0

// YCombinator
function anonymous(fnc) {
  return function() {
    fnc.apply(fnc, arguments);
    return fnc;
  }
}

// Invoking the first time:
setInterval(anonymous(function() {
  console.log("bar");
})(), 4000);

// Not invoking the first time:
setInterval(anonymous(function() {
  console.log("foo");
}), 4000);
// Or simple:
setInterval(function() {
  console.log("baz");
}, 4000);

Ok, das ist so komplex, also lassen Sie es mich einfacher sagen:

function hello(status ) {    
  console.log('world', ++status.count);
  
  return status;
}

setInterval(hello, 5 * 1000, hello({ count: 0 }));

NSD
quelle
Dies ist weit überentwickelt.
Polyducks
0

Sie können eine sehr kleine anfängliche Verzögerungszeit (z. B. 100) einstellen und diese innerhalb der Funktion auf die gewünschte Verzögerungszeit einstellen:

var delay = 100;

function foo() {
  console.log("Change initial delay-time to what you want.");
  delay = 12000;
  setTimeout(foo, delay);
}

reo_yamanaka
quelle
-2

Es gibt ein Problem mit dem sofortigen asynchronen Aufruf Ihrer Funktion, da standardmäßig setTimeout / setInterval ein minimales Zeitlimit von einigen Millisekunden aufweist, selbst wenn Sie es direkt auf 0 setzen. Dies wird durch eine browserspezifische Arbeit verursacht.

Ein Beispiel für Code mit einer REALEN Verzögerung von Null, der in Chrome, Safari und Opera funktioniert

function setZeroTimeout(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage('');
}

Weitere Informationen finden Sie hier

Und nach dem ersten Handaufruf können Sie mit Ihrer Funktion ein Intervall erstellen.

Xe-Xe
quelle
-10

eigentlich ist das am schnellsten zu tun

interval = setInterval(myFunction(),45000)

Dies ruft meine Funktion auf und führt sie dann alle 45 Sekunden erneut aus, was sich von der Ausführung unterscheidet

interval = setInterval(myfunction, 45000)

das wird es nicht nennen, sondern nur planen

Hertzel Armengol
quelle
Woher hast du das?
Ken Sharp
2
Dies funktioniert nur, wenn myFunction()es sich selbst zurückgibt. Stattdessen setIntervalist es besser, jede Funktion, die von ihr aufgerufen werden soll, so zu ändern, dass sie setIntervaleinmal umbrochen wird, wie es die anderen Antworten vorschlagen.
Jens Wirth