Eseguire la funzione setInterval senza indugio la prima volta


341

Esiste un modo per configurare il setIntervalmetodo di JavaScript per eseguire immediatamente il metodo e quindi eseguire con il timer


4
Non nativamente però. Puoi provare a chiamare functionuna volta e poi a faresetInterval()
Mrchief il

Risposte:


519

È più semplice chiamare la funzione da soli direttamente la prima volta:

foo();
setInterval(foo, delay);

Tuttavia ci sono buone ragioni per evitare setInterval- in particolare in alcune circostanze un intero carico di setIntervaleventi può arrivare immediatamente uno dopo l'altro senza alcun ritardo. Un altro motivo è che se si desidera interrompere il ciclo, è necessario chiamare esplicitamente, il clearIntervalche significa che è necessario ricordare l'handle restituito dalla setIntervalchiamata originale .

Quindi un metodo alternativo è quello di fooattivarsi per le chiamate successive usando setTimeoutinvece:

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

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

// start the cycle
foo();

Ciò garantisce che vi sia almeno un intervallo delaytra le chiamate. Inoltre, rende più semplice l'annullamento del loop, se necessario, semplicemente non si chiamasetTimeout quando viene raggiunta la condizione di terminazione del loop.

Meglio ancora, puoi concludere tutto in un'espressione di funzione immediatamente invocata che crea la funzione, che quindi si chiama di nuovo come sopra e avvia automaticamente il ciclo:

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

che definisce la funzione e avvia il ciclo tutto in una volta.


5
Perché preferisci setTimeout?
Sanghyun Lee,

19
@Sangdol perché garantisce che gli eventi timer non si "impilano" se non vengono elaborati. In alcune circostanze un intero carico di setIntervaleventi può arrivare immediatamente uno dopo l'altro senza alcun ritardo.
Alnitak,

8
Dovrebbe esserci una specie di test che non ti consente di pubblicare in pila quando sei stanco
James,

3
Come posso interrompere la funzione se utilizzo il setTimeoutmetodo?
Gaurav Bhor,

6
@DaveMunger no, perché non è veramente ricorsivo - è solo "pseudo-ricorsivo". Le chiamate "ricorsive" non si verificano fino a quando il browser non ritorna al loop degli eventi, a quel punto lo stack di chiamate è stato completamente svolto.
Alnitak,

210

Non sono sicuro di capirti correttamente, ma potresti facilmente fare qualcosa del genere:

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

Esistono ovviamente molti modi per farlo, ma è il modo più conciso a cui riesco a pensare.


16
Questa è una bella risposta perché è una funzione denominata che viene eseguita immediatamente e restituisce anche se stessa. Esattamente quello che stavo cercando.
jmort253,

41
Sicuramente una soluzione interessante, ma che potrebbe creare confusione per le persone che leggono in futuro.
Deepak Joy,

4
Non è necessario dargli un nome "ciao". Potresti invece restituire argomenti.callee e avere lo stesso con una funzione anonima
JochenJung

10
@JochenJung arguments.calleenon è disponibile in modalità ES5 rigorosa
Alnitak il

3
Questo è il tipo di codice Javascript che confonderà la maggior parte dei nuovi programmatori JS che provengono da altre lingue. Scrivi un sacco di cose come questa se la tua azienda non ha molto personale JS e desideri la sicurezza del lavoro.
Ian,

13

Mi sono imbattuto in questa domanda a causa dello stesso problema, ma nessuna delle risposte aiuta se devi comportarti esattamente come, setInterval()ma con l' unica differenza che la funzione viene chiamata immediatamente all'inizio.

Ecco la mia soluzione a questo problema:

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

Il vantaggio di questa soluzione:

  • l'utilizzo del codice esistente setIntervalpuò essere facilmente adattato mediante sostituzione
  • funziona in modalità rigorosa
  • funziona con le funzioni e le chiusure nominate esistenti
  • puoi comunque utilizzare il valore restituito e passarlo a clearInterval()più tardi

Esempio:

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

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

Per essere sfacciato, se hai davvero bisogno di usare, setIntervalpuoi anche sostituire l'originale setInterval. Pertanto, non è necessario modificare il codice quando si aggiunge questo prima del codice esistente:

var setIntervalOrig = setInterval;

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

Tuttavia, tutti i vantaggi sopra elencati si applicano qui, ma non è necessaria alcuna sostituzione.


Preferisco questa soluzione alla setTimeoutsoluzione perché restituisce un setIntervaloggetto. Per evitare di chiamare funzioni che potrebbero essere più avanti nel codice e quindi non definite al momento attuale, avvolgo la prima chiamata di funzione in una setTimeoutfunzione come questa: setTimeout(function(){ func();},0);La prima funzione viene quindi chiamata dopo l'attuale ciclo di elaborazione, che è anche immediatamente , ma è più errore dimostrato.
pensan

8

Potresti avvolgere setInterval()una funzione che fornisce quel comportamento:

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

... quindi usalo in questo modo:

instantGratification( function() {
    console.log( 'invoked' );
}, 3000);

5
Penso che dovresti restituire ciò che restituisce setInterval. Questo perché altrimenti non è possibile utilizzare clearInterval.
Henrik R,

5

Ecco un wrapper per cercarlo abbastanza se ne hai bisogno:

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

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

Imposta il terzo argomento di setInterval su true e verrà eseguito per la prima volta immediatamente dopo aver chiamato setInterval:

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

O ometti il ​​terzo argomento e manterrà il suo comportamento originale:

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

Alcuni browser supportano argomenti aggiuntivi per setInterval di cui questo wrapper non tiene conto; Penso che questi vengano usati raramente, ma tienilo a mente se ne hai bisogno.


9
Sostituire le funzioni del browser nativo è terribile poiché può rompere altri codici coesistenti quando cambiano le specifiche. In effetti, setInterval attualmente ha più parametri: developer.mozilla.org/en-US/docs/Web/API/WindowTimers/…
Áxel Costas Pena

2

Perché qualcuno ha bisogno di portare l'esterno thisall'interno come se fosse una funzione freccia.

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

Se la spazzatura che produce sopra ti dà fastidio, puoi invece effettuare una chiusura.

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

O forse considera l'utilizzo del @autobinddecoratore a seconda del tuo codice.


1

Suggerirò di chiamare le funzioni nella seguente sequenza

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

È inoltre possibile passare il _timeral foo, se si desidera a clearInterval(_timer)una determinata condizione

var _timer = setInterval(function() { foo(_timer, params) }, delay);
foo(_timer, params);

Potresti spiegarlo in modo più approfondito?
Polyducks,

imposti il ​​timer dalla seconda chiamata, per la prima volta chiami direttamente il fn.
Jayant Varshney,

1

Ecco una versione semplice per i principianti senza tutto il casino. Dichiara semplicemente la funzione, la chiama, quindi avvia l'intervallo. Questo è tutto.

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


1
Questo è esattamente ciò che fa la risposta accettata nella prima riga. In che modo questa risposta aggiunge qualcosa di nuovo?
Dan Dascalescu

La risposta accettata continua dicendo di non farlo. La mia risposta alla risposta accettata spiega perché è ancora un metodo valido. L'OP chiede specificamente di chiamare la funzione setInterval alla sua prima chiamata, ma la risposta accettata devia per parlare dei vantaggi di setTimeout.
Polyducks,

0

Per risolvere questo problema, eseguo la funzione una prima volta dopo il caricamento della pagina.

function foo(){ ... }

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

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

0

C'è un comodo pacchetto npm chiamato firstInterval (divulgazione completa, è mio).

Molti degli esempi qui non includono la gestione dei parametri e cambiare i comportamenti predefiniti di setIntervalqualsiasi progetto di grandi dimensioni è male. Dai documenti:

Questo modello

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

è identico a

firstInterval(callback, 1000, p1, p2);

Se sei una vecchia scuola nel browser e non vuoi la dipendenza, è un semplice taglia e incolla dal codice.


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, questo è così complesso, quindi, lasciami dire più semplice:

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

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


Questo è enormemente ingegnerizzato.
Polyducks,

0

È possibile impostare un ritardo iniziale molto piccolo (ad es. 100) e impostarlo sul ritardo desiderato all'interno della funzione:

var delay = 100;

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


-2

C'è un problema con la chiamata asincrona immediata della tua funzione, perché setTimeout / setInterval standard ha un timeout minimo di diversi millisecondi anche se lo imposti direttamente a 0. È causato da un lavoro specifico del browser.

Un esempio di codice con un ritardo zero REALE che funziona in Chrome, Safari, Opera

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

Puoi trovare maggiori informazioni qui

E dopo la prima chiamata manuale è possibile creare un intervallo con la propria funzione.


-10

in realtà il più veloce è fare

interval = setInterval(myFunction(),45000)

questo chiamerà myfunction, e poi lo farà agaian ogni 45 secondi, il che è diverso dal fare

interval = setInterval(myfunction, 45000)

che non lo chiamerà, ma solo programmarlo


Da dove l'hai preso?
Ken Sharp

2
Funziona solo se myFunction()ritorna da solo. Invece, modificare ogni funzione che deve essere chiamata da setIntervalessa è un approccio migliore per concludere setIntervaluna volta come le altre risposte propongono.
Jens Wirth,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.