setTimeout o setInterval?


763

Per quanto ne so, questi due pezzi di javascript si comportano allo stesso modo:

Opzione A:

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

myTimeoutFunction();

Opzione B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

C'è qualche differenza tra l'uso di setTimeout e setInterval ?


6
Se desideri dei buoni dettagli su come funzionano i timer in JS, John Resig ha scritto un buon articolo su questo argomento
Rafael,

9
c'è anche l'ovvia differenza che setTimeout richiede quella riga aggiuntiva di codice per mantenerlo propagato, che ha lo svantaggio di essere un problema di manutenzione ma il vantaggio di permetterti di cambiare facilmente il periodo
annakata


4
Grazie @JapanPro ma non ho mai avuto problemi a far funzionare i timeout. Questo post parlava di quale fosse la differenza e quale dovrebbe essere usato.
Damovisa,

Risposte:


670

Sostanzialmente cercano di fare la stessa cosa, ma l' setIntervalapproccio sarà più accurato setTimeoutdell'approccio, poiché setTimeoutattende 1000 ms, esegue la funzione e quindi imposta un altro timeout. Quindi il periodo di attesa è in realtà un po 'più di 1000ms (o molto di più se la tua funzione impiega molto tempo per essere eseguita).

Anche se si potrebbe pensare che setIntervaleseguirà esattamente ogni 1000ms, è importante notare chesetInterval ritarderà, poiché JavaScript non è un linguaggio multi-thread, il che significa che - se ci sono altre parti dello script in esecuzione - l'intervallo avrà aspettare che finisca.

In questo violino , puoi vedere chiaramente che il timeout resterà indietro, mentre l'intervallo è quasi sempre a quasi 1 chiamata / secondo (cosa che lo script sta cercando di fare). Se cambi la variabile di velocità in alto in qualcosa di piccolo come 20 (nel senso che proverà a correre 50 volte al secondo), l'intervallo non raggiungerà mai una media di 50 iterazioni al secondo.

Il ritardo è quasi sempre trascurabile, ma se stai programmando qualcosa di veramente preciso, dovresti optare per un timer autoregolante (che essenzialmente è un timer basato sul timeout che si regola costantemente per il ritardo che viene creato)


4
Andy aveva un suggerimento simile. Ipoteticamente, questo significa che se il metodo impiega più di 1000ms per essere eseguito, puoi averne più di uno in esecuzione contemporaneamente?
Damovisa,

14
Teoricamente si. In pratica, no poiché Javascript non supporta il multithreading. Se il tuo codice impiega più di 1000 ms, bloccherà il browser.
Kamiel Wanrooij,

61
Tecnicamente, il codice non verrà eseguito esattamente ogni 1000 ms, poiché dipende dalla risoluzione del timer e dall'eventuale esecuzione di altro codice. Il tuo punto è ancora valido.
Matthew Crumley,

10
setInterval è diverso in due modi, 1. setInterval non è ricorsivo e setInterval chiamerà per la prima volta la tua funzione dopo l'ora indicata, mentre setTimeout viene chiamato per la prima volta senza alcun ritardo e successivamente richiamerà dopo l'ora indicata. Dopo la prima esecuzione funzionano quasi allo stesso modo.
Hafiz,

5
La differenza è che setTimeout non si ripete. Ti permette di eseguire uno script dopo un tempo prestabilito, ma solo una volta. SetInterval invece ripeterà quello script, fino a quando non viene interrotto con clearTimeout ().
Leander

648

C'è qualche differenza?

Sì. Un timeout esegue un determinato periodo di tempo dopo la chiamata di setTimeout (); un intervallo esegue un certo periodo di tempo dopo l'intervallo precedente attivato.

Noterai la differenza se la tua funzione doStuff () richiede del tempo per essere eseguita. Ad esempio, se rappresentiamo una chiamata a setTimeout / setInterval con ., l'attivazione del timeout / intervallo con *e l'esecuzione del codice JavaScript con [-----], le linee temporali appaiono come:

Timeout:

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

Interval:

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

La prossima complicazione è se un intervallo scatta mentre JavaScript è già occupato a fare qualcosa (come gestire un intervallo precedente). In questo caso, l'intervallo viene ricordato e si verifica non appena il gestore precedente termina e restituisce il controllo al browser. Ad esempio, per un processo doStuff () che a volte è breve ([-]) e talvolta lungo ([-----]):

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

• rappresenta un intervallo di attivazione che non è stato in grado di eseguire immediatamente il suo codice ed è stato invece sospeso.

Quindi gli intervalli cercano di "recuperare" per tornare nei tempi previsti. Ma non si mettono in coda uno sopra l'altro: può esserci solo una esecuzione in sospeso per intervallo. (Se fossero tutti in coda, il browser verrebbe lasciato con un elenco in continua espansione di esecuzioni eccezionali!)

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

x rappresenta un intervallo di attivazione che non può essere eseguito o reso in sospeso, quindi è stato scartato.

Se la tua funzione doStuff () impiega abitualmente più tempo dell'esecuzione rispetto all'intervallo impostato, il browser consumerà il 100% della CPU nel tentativo di ripararla e potrebbe diventare meno reattivo.

Quale usi e perché?

Chained-Timeout offre uno slot di tempo libero garantito al browser; L'intervallo cerca di garantire che la funzione in esecuzione venga eseguita il più vicino possibile agli orari pianificati, a scapito della disponibilità dell'interfaccia utente del browser.

Considererei un intervallo per le animazioni una tantum che volevo essere il più fluido possibile, mentre i timeout concatenati sono più educati per le animazioni in corso che si verificherebbero continuamente mentre la pagina viene caricata. Per usi meno impegnativi (come un banale programma di aggiornamento che si attiva ogni 30 secondi o qualcosa del genere), puoi tranquillamente utilizzare entrambi.

In termini di compatibilità del browser, setTimeout precede setInterval, ma tutti i browser che incontrerai oggi supportano entrambi. L'ultimo sbandato per molti anni è stato IE Mobile in WinMo <6.5, ma speriamo che anche questo sia alle spalle.


Ma il motivo della scelta tra Interval e Timeout vale anche per piattaforme non browser, come ad esempio WebOS o JIL?
Vid L

2
Un bel modo di fare timeout concatenati su funzioni anonime: setTimeout (function () {setTimeout (argomenti.callee, 10)}, 10)
Justin Meyer

1
In termini di compatibilità del browser, sebbene tutti i browser forniscano entrambi i metodi, le loro prestazioni sono diverse.
unigg,

"Ma allora è probabile che non supporti nient'altro che stai usando" così vero
Basic

1
drum machine del progetto chromium usando setTimeout ("schedule ()", 0); Quindi il browser non avrà stack inutili quando è in background per Chrome o mancanza di risorse.
Elliot Yap,

91

setInterval ()

setInterval()è un metodo di esecuzione del codice basato su intervallo di tempo che ha la capacità nativa di eseguire ripetutamente uno script specificato quando viene raggiunto l'intervallo. Dovrebbe non essere annidato nella sua funzione di callback dall'autore script per renderlo ciclo, dal momento che loop di default . Continuerà a sparare a intervalli a meno che non chiami clearInterval().

Se si desidera eseguire il loop del codice per le animazioni o con un segno di spunta dell'orologio, utilizzare setInterval().

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

setTimeout ()

setTimeout()è un metodo di esecuzione del codice basato sul tempo che eseguirà uno script una sola volta quando viene raggiunto l'intervallo. Sarà Non ripetere a meno che non attrezzarsi al ciclo lo script nidificazione l' setTimeout()interno oggetto della funzione che chiama a correre. Se impostato su loop, continuerà a sparare all'intervallo a meno che non chiami clearTimeout().

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

Se si desidera che accada qualcosa una volta dopo un periodo di tempo specificato, utilizzare setTimeout(). Questo perché viene eseguito solo una volta quando viene raggiunto l'intervallo specificato.


6
Bella spiegazione ma nota che l'OP comprende la differenza di base negli esempi forniti dall'OP. In particolare, si noti che nel PO setTimeout()esempio, setTimeout()è chiamato ricorsivamente , mentre setInterval()non lo è.
DavidRR

44

SetInterval semplifica l'annullamento dell'esecuzione futura del codice. Se si utilizza setTimeout, è necessario tenere traccia dell'ID timer nel caso in cui si desideri annullarlo in seguito.

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

myTimeoutFunction();

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

contro

function myTimeoutFunction()
{
    doStuff();
}

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

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

35
Non vedo come non stai tenendo traccia dell'ID timer nel caso di setInterval. È appena uscito dalla funzione.
Kekoa,

1
Un'altra opzione con setTimeoutè piuttosto che salvare l'id aggiungere ifun'istruzione per impostare il timeout successivo solo quando alcune condizioni sono vere.
nnnnnn,

7
Kekoa, buon punto. Ma devi salvare l'ID intervallo solo una volta. L'ID timeout sta probabilmente cambiando ad ogni invocazione, quindi è necessario tenere traccia di queste modifiche. Il codice che vuole cancellare il timeout deve in qualche modo avere accesso al valore corrente di questa variabile. Inoltre, è impossibile cancellare il timeout durante l'esecuzione doStuffperché l'id non è valido. Tuttavia, non è davvero necessario salvare gli ID di timeout. Invece puoi semplicemente smettere di chiamare setTimeout.
Robert

4
Nella mia esperienza, la maggior parte delle volte vuoi essere in grado di annullare anche usando setTimeout. Il 99% delle volte che si desidera annullare prima che si verifichi la chiamata successiva, non al termine di quella successiva.
Kamiel Wanrooij,

23

Trovo il setTimeoutmetodo più facile da usare se si desidera annullare il timeout:

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

myTimeoutFunction();

Inoltre, se qualcosa dovesse andare storto nella funzione, smetterebbe di ripetersi al primo errore, invece di ripetere l'errore ogni secondo.


20

La vera differenza sta nei loro scopi.

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

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

E 'così semplice

Dettagli più elaborati qui http://javascript.info/tutorial/settimeout-setinterval


7
Bella spiegazione concisa ma nota che l'OP comprende la differenza di base negli esempi forniti dall'OP. In particolare, si noti che nel PO setTimeout()esempio, setTimeout()è chiamato ricorsivamente , mentre setInterval()non lo è.
DavidRR

14

Quando si esegue una funzione all'interno di setInterval, che funziona più del timeout-> il browser si bloccherà.

- Ad esempio, doStuff () richiede 1500 sec. per essere eseguito e lo fai: setInterval (doStuff, 1000);
1) Il browser esegue doStuff () che impiega 1,5 sec. essere giustiziato;
2) Dopo ~ 1 secondo tenta di eseguire nuovamente doStuff () . Ma il precedente doStuff () è ancora eseguito-> quindi il browser aggiunge questa corsa alla coda (da eseguire dopo averla prima eseguita).
3,4, ..) La stessa aggiunta alla coda di esecuzione per le successive iterazioni, ma doStuff () dalla precedente sono ancora in corso ...
Di conseguenza, il browser è bloccato.

Per evitare questo comportamento, il modo migliore è eseguire setTimeout all'interno di setTimeout per emulare setInterval .
Per correggere i timeout tra le chiamate setTimeout, è possibile utilizzare l'alternativa autocorrettiva alla tecnica setInterval di JavaScript .


1
Non so perché nessuno abbia trovato alcun valore in questa risposta!
Randika Vishman,

9

Uso setTimeout.

Apparentemente la differenza è impostataTimeout chiama il metodo una volta, setInterval lo chiama ripetutamente.

Ecco un buon articolo che spiega la differenza: Tutorial: timer JavaScript con setTimeout e setInterval


2
Sì, ho avuto quella differenza, ma i due pezzi di codice che ho fornito dovrebbero fare la stessa cosa ...
Damovisa,

Ummm si ... avrei pensato ... ma secondo Dcaunt e il suo voto conta non è proprio quello che succede.
Bravax,

9

Il tuo codice avrà numeri di esecuzione diversi e in alcuni progetti, come i giochi online, non è accettabile. Innanzitutto, cosa dovresti fare, per far funzionare il tuo codice con gli stessi numeri interi, dovresti cambiare "myTimeoutFunction" in questo:

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

Dopo questa modifica, sarà uguale a

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

Tuttavia, non avrai ancora risultati stabili, perché JS è a thread singolo. Per ora, se il thread JS sarà occupato con qualcosa, non sarà in grado di eseguire la funzione di callback e l'esecuzione verrà posticipata di 2-3 msec. Se hai 60 esecuzioni al secondo e ogni volta che hai un ritardo casuale di 1-3 secondi, non sarà assolutamente accettabile (dopo un minuto ci saranno circa 7200 msec di ritardo) e posso consigliarti di usare qualcosa del genere:

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

Questo codice garantirà un periodo di esecuzione stabile. Anche il thread sarà occupato e il tuo codice verrà eseguito dopo 1005 msecondi, la prossima volta avrà timeout per 995 msec e il risultato sarà stabile.


7

Ho fatto un semplice test di setInterval(func, milisec), perché ero curioso di sapere cosa succede quando il consumo di tempo di funzione è maggiore della durata dell'intervallo.

setIntervalsarà generalmente pianificare successiva iterazione appena dopo l' inizio della iterazione precedente, a meno che la funzione è ancora in corso . In tal caso, setIntervalattenderà fino al termine della funzione. Non appena si verifica, la funzione viene immediatamente attivata nuovamente: non è possibile attendere la prossima iterazione secondo il programma (poiché sarebbe in condizioni senza funzione superata nel tempo). Non esiste inoltre alcuna situazione con iterazioni parallele in esecuzione.

Ho provato questo su Chrome v23. Spero sia un'implementazione deterministica in tutti i browser moderni.

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

Uscita console:

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

La waitfunzione è solo un helper che blocca i thread - chiamata ajax sincrona che richiede esattamente 2500 millisecondi di elaborazione sul lato server:

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

1
"nessuna situazione con iterazioni parallele in esecuzione" - sì, questo dovrebbe essere impossibile. JavaScript lato client ha un modello di esecuzione a thread singolo, quindi non accade mai nulla (gestori di eventi, ecc.) Contemporaneamente. Ecco perché non succede nulla (e il browser non risponde) durante la chiamata ajax sincrona.
Mr White,

Il browser risponde in pochi ms tra "intervalli"? Un altro evento si attiva se è in sospeso? (Grazie per i test tra +1)
MrWhite

1
Secondo MDN, è considerato " utilizzo pericoloso " se la funzione potrebbe essere eseguita per un periodo di tempo superiore a quello dell'intervallo. È setTimoutpreferibile una chiamata ricorsiva .
MrWhite,

6

Per guardarlo in modo un po 'diverso: setInterval assicura che un codice venga eseguito ad ogni dato intervallo (cioè 1000ms, o quanto si specifica) mentre setTimeout imposta il tempo che "attende fino a" quando esegue il codice. E poiché sono necessari millisecondi aggiuntivi per eseguire il codice, si aggiungono fino a 1000ms e, quindi, setTimeout viene eseguito di nuovo a orari inesatti (oltre 1000ms).

Ad esempio, i timer / i conti alla rovescia non vengono eseguiti con setTimeout, ma con setInterval, per garantire che non torni e che il codice venga eseguito all'intervallo specificato.


5

Sia setInterval che setTimeout restituiscono un ID timer che è possibile utilizzare per annullare l'esecuzione, ovvero prima che vengano attivati ​​i timeout. Per annullare la chiamata, chiamare clearInterval o clearTimeout in questo modo:

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

Inoltre, i timeout vengono automaticamente annullati quando si esce dalla pagina o si chiude la finestra del browser.


4

Puoi validare la risposta di bobince da solo quando esegui il seguente javascript o controlli questo 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

Bene, setTimeout è migliore in una situazione, come ho appena imparato. Uso sempre setInterval, che mi rimane da eseguire in background per più di mezz'ora. Quando sono tornato a quella scheda, la presentazione (su cui è stato utilizzato il codice) stava cambiando molto rapidamente, anziché ogni 5 secondi che avrebbe dovuto avere. Succede di nuovo quando lo collaudo di più e se è colpa del browser o meno non è importante, perché con setTimeout quella situazione è completamente impossibile.


Sembra che tu abbia chiamato setInterval all'interno della funzione che stavi chiamando. È così che esegui il ciclo con setTimeout, ma con setInterval in realtà crei un ciclo completamente nuovo ogni volta che viene chiamato.
Stephen R,


2

Aggiungendo semplicemente ciò che è già stato detto, ma la versione setTimeout del codice raggiungerà anche quella Maximum call stack sizeche ne impedirà il funzionamento. Poiché non esiste un caso base in cui la funzione ricorsiva si fermi, non è possibile eseguirla per sempre.



-1

La differenza più generica tra e setInterval (espressione, durata) è quella

setTimeout () eseguirà l'espressione UNA VOLTA e quella dopo quella durata specificata.

Però,

setInterval () eseguirà l'espressione in INFINITE-LOOP dopo ogni durata specificata.


-5

Penso SetIntervale SetTimeoutsono diversi. SetIntervalesegue il blocco in base al tempo impostato mentre,SetTimeout esegue il blocco di codice una volta.

Prova questo set di codici dopo i secondi del conto alla rovescia del timeout:

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

e poi prova

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

Puoi vedere le differenze per te stesso.


Questo non risponde alla domanda. settimeout () può essere usato in modo ricorsivo per dare lo stesso risultato di setinterval. La domanda riguardava le prestazioni di queste due opzioni.
Tomas Gonzalez,
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.