setTimeout o setInterval?

763

Por lo que puedo decir, estas dos piezas de JavaScript se comportan de la misma manera:

Opcion A:

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

myTimeoutFunction();

Opcion B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

¿Hay alguna diferencia entre usar setTimeout y setInterval ?

Damovisa
fuente
66
Si desea algunos buenos detalles sobre cómo funcionan los temporizadores en JS, John Resig escribió un buen artículo sobre este tema
Rafael
99
también existe la diferencia obvia de que setTimeout requiere que la línea de código adicional para evitar que se propaga, que tiene el inconveniente de ser un problema de mantenimiento, pero la ventaja de que le permite cambiar fácilmente el período
annakata
prueba esto jsfiddle.net/pramendra/Y4vEV
Pramendra Gupta
44
Gracias @JapanPro, pero nunca tuve problemas para hacer que los tiempos de espera funcionen. Esta publicación fue sobre cuál era la diferencia y cuál debería usarse.
Damovisa

Respuestas:

670

Básicamente intentan hacer lo mismo, pero el setIntervalenfoque será más preciso que el setTimeoutenfoque, ya quesetTimeout espera 1000 ms, ejecuta la función y luego establece otro tiempo de espera. Por lo tanto, el período de espera es en realidad un poco más de 1000 ms (o mucho más si su función tarda mucho en ejecutarse).

Aunque uno podría pensar que setIntervalse ejecutará exactamente cada 1000 ms, es importante tener en cuenta quesetInterval también se retrasará, ya que JavaScript no es un lenguaje multiproceso, lo que significa que, si hay otras partes del script en ejecución, el intervalo tendrá esperar a que eso termine.

En este Fiddle , puede ver claramente que el tiempo de espera se retrasará, mientras que el intervalo es casi todo el tiempo en casi 1 llamada / segundo (que el script está tratando de hacer). Si cambia la variable de velocidad en la parte superior a algo pequeño como 20 (lo que significa que intentará ejecutarse 50 veces por segundo), el intervalo nunca alcanzará un promedio de 50 iteraciones por segundo.

El retraso casi siempre es insignificante, pero si está programando algo realmente preciso, debe optar por un temporizador autoajustable (que esencialmente es un temporizador basado en el tiempo de espera que se ajusta constantemente por el retraso que se crea)

David Snabel-Caunt
fuente
44
Andy tenía una sugerencia similar. Hipotéticamente, ¿significa esto que si el método tarda más de 1000 ms en ejecutarse, puede tener más de uno ejecutándose simultáneamente?
Damovisa
14
Teóricamente, sí. En la práctica, no, ya que Javascript no admite subprocesos múltiples. Si su código tarda más de 1000 ms, congelará el navegador.
Kamiel Wanrooij
61
Técnicamente, el código no se ejecutará exactamente cada 1000 ms, ya que depende de la resolución del temporizador y de si ya se está ejecutando otro código. Sin embargo, tu punto sigue en pie.
Matthew Crumley
10
setInterval es diferente de dos maneras, 1. setInterval no es recursivo y setInterval llamará por primera vez a su función después de la hora indicada, mientras que setTimeout se llamará por primera vez sin demora y luego volverá a llamar después de la hora indicada. Después de la primera ejecución funcionan casi igual.
Hafiz
55
La diferencia es que setTimeout no se repite. Le permite ejecutar un script después de un tiempo establecido, pero solo una vez. Por otro lado, setInterval repetirá ese script, hasta que se detenga con clearTimeout ().
Leander
648

¿Hay alguna diferencia?

Si. Un tiempo de espera ejecuta una cierta cantidad de tiempo después de llamar a setTimeout (); un intervalo ejecuta una cierta cantidad de tiempo después del disparo del intervalo anterior.

Notará la diferencia si su función doStuff () tarda un tiempo en ejecutarse. Por ejemplo, si representamos una llamada a setTimeout / setInterval con ., un disparo del tiempo de espera / intervalo con *y la ejecución del código JavaScript con [-----], las líneas de tiempo se verán así:

Timeout:

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

Interval:

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

La siguiente complicación es si se dispara un intervalo mientras JavaScript ya está ocupado haciendo algo (como manejar un intervalo anterior). En este caso, el intervalo se recuerda y ocurre tan pronto como el controlador anterior finaliza y devuelve el control al navegador. Entonces, por ejemplo, para un proceso doStuff () que a veces es corto ([-]) y a veces largo ([-----]):

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

• representa un disparo de intervalo que no pudo ejecutar su código de inmediato, y se hizo pendiente en su lugar.

Por lo tanto, los intervalos intentan "ponerse al día" para volver a su horario. Pero no hacen cola una encima de la otra: solo puede haber una ejecución pendiente por intervalo. (¡Si todos se pusieran en cola, el navegador se quedaría con una lista cada vez mayor de ejecuciones pendientes!)

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

x representa un disparo de intervalo que no se pudo ejecutar o quedar pendiente, por lo que se descartó.

Si su función doStuff () habitualmente tarda más en ejecutarse que el intervalo establecido, el navegador consumirá el 100% de la CPU que intenta repararla y puede volverse menos receptiva.

¿Cuál usas y por qué?

Chained-Timeout ofrece un espacio garantizado de tiempo libre para el navegador; Interval intenta garantizar que la función que ejecuta se ejecute lo más cerca posible de sus tiempos programados, a expensas de la disponibilidad de la interfaz de usuario del navegador.

Consideraría un intervalo para animaciones únicas que quería que fuera lo más suave posible, mientras que los tiempos de espera encadenados son más amables para las animaciones en curso que tendrían lugar todo el tiempo mientras se carga la página. Para usos menos exigentes (como un actualizador trivial disparando cada 30 segundos o algo así), puede usar cualquiera de los dos de manera segura.

En términos de compatibilidad del navegador, setTimeout es anterior a setInterval, pero todos los navegadores que conocerá hoy son compatibles con ambos. El último rezagado durante muchos años fue IE Mobile en WinMo <6.5, pero espero que eso también haya quedado atrás.

bobince
fuente
Pero, ¿el motivo de elección entre Intervalo y Tiempo de espera es válido incluso para plataformas que no son del navegador, como por ejemplo WebOS o JIL?
Vid L
2
Una buena manera de hacer tiempos de espera encadenados en funciones anónimas: setTimeout (function () {setTimeout (argumentos.callee, 10)}, 10)
Justin Meyer
1
En términos de compatibilidad del navegador, aunque todos los navegadores proporcionan ambos métodos, su rendimiento es diferente.
unigg
"Pero lo más probable es que no es compatible con cualquier otra cosa que esté utilizando ya sea" tan cierto
Básico
1
caja de ritmos por proyecto de cromo usando setTimeout ("schedule ()", 0); Por lo tanto, el navegador no tendrá una pila innecesaria cuando se trata de una pestaña de fondo para Chrome o falta de recursos.
Elliot Yap
91

setInterval ()

setInterval()es un método de ejecución de código basado en intervalos de tiempo que tiene la capacidad nativa de ejecutar repetidamente un script específico cuando se alcanza el intervalo. El autor del script no debe anidarlo en su función de devolución de llamada para que se repita, ya que se repite de forma predeterminada . Seguirá disparando a intervalos, a menos que llame clearInterval().

Si desea hacer un bucle de código para animaciones o en una marca de reloj, úselo setInterval().

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

setTimeout ()

setTimeout()es un método de ejecución de código basado en el tiempo que ejecutará un script solo una vez cuando se alcance el intervalo. Será no repetir de nuevo a menos que lo orientan hacia bucle de la secuencia de comandos anidando el setTimeout()interior de objeto de la función que llama a ejecutar. Si está orientado al bucle, seguirá disparando en el intervalo a menos que llame clearTimeout().

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

Si desea que algo suceda una vez después de un período de tiempo específico, úselo setTimeout(). Esto se debe a que solo se ejecuta una vez cuando se alcanza el intervalo especificado.

Haris
fuente
66
Buena explicación, pero tenga en cuenta que el OP entiende la diferencia básica en los ejemplos que el OP proporcionó. En particular, tenga en cuenta que en el setTimeout()ejemplo del OP , setTimeout()se llama de forma recursiva , mientras setInterval()que no.
DavidRR
44

SetInterval hace que sea más fácil cancelar la ejecución futura de su código. Si usa setTimeout, debe realizar un seguimiento de la identificación del temporizador en caso de que desee cancelarlo más adelante.

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

myTimeoutFunction();

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

versus

function myTimeoutFunction()
{
    doStuff();
}

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

// later on...
clearInterval(timerId);
Kamiel Wanrooij
fuente
35
No veo cómo no realiza un seguimiento de la identificación del temporizador en el caso de setInterval. Se acaba de sacar de la función.
Kekoa
1
Otra opción con setTimeoutes, en lugar de guardar la identificación, agregar una ifinstrucción para establecer solo el próximo tiempo de espera cuando se cumpla alguna condición.
nnnnnn
77
Kekoa, buen punto. Pero debe guardar la identificación del intervalo solo una vez. El ID de tiempo de espera probablemente cambia con cada invocación, por lo que debe realizar un seguimiento de estos cambios. El código que quiere borrar el tiempo de espera debe tener acceso al valor actual de esta variable. Además, es imposible borrar el tiempo de espera mientras se ejecuta doStuffporque la identificación no es válida. Sin embargo, no es realmente necesario guardar identificadores de tiempo de espera. En cambio, puedes dejar de llamar setTimeout.
Robert
44
En mi experiencia, la mayoría de las veces quieres poder cancelar incluso mientras usas setTimeout. 99% del tiempo que desea cancelar antes de que ocurra la próxima invocación, no después de que finalice la siguiente.
Kamiel Wanrooij
23

Creo que el setTimeoutmétodo es más fácil de usar si desea cancelar el tiempo de espera:

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

myTimeoutFunction();

Además, si algo sale mal en la función, simplemente dejará de repetirse al primer error, en lugar de repetir el error cada segundo.

Guffa
fuente
20

La verdadera diferencia está en sus propósitos.

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

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

Es tan simple como eso

Detalles más elaborados aquí http://javascript.info/tutorial/settimeout-setinterval

kmario23
fuente
77
Buena explicación concisa, pero tenga en cuenta que el OP comprende la diferencia básica en los ejemplos que el OP proporcionó. En particular, tenga en cuenta que en el setTimeout()ejemplo del OP , setTimeout()se llama de forma recursiva , mientras setInterval()que no.
DavidRR
14

Cuando ejecuta alguna función dentro de setInterval, que funciona más tiempo que timeout-> el navegador se bloqueará.

- Por ejemplo, doStuff () tarda 1500 segundos. para ejecutar y lo haces: setInterval (doStuff, 1000);
1) El navegador ejecuta doStuff () que tarda 1,5 segundos. ser ejecutado
2) Después de ~ 1 segundo, intenta ejecutar doStuff () nuevamente. Pero doStuff () anterior todavía se ejecuta- > por lo que el navegador agrega esta ejecución a la cola (para ejecutarse después de que se haya hecho primero).
3,4, ..) Lo mismo que se agrega a la cola de ejecución para las próximas iteraciones, pero doStuff () de anteriores todavía están en progreso ...
Como resultado, el navegador está atascado.

Para evitar este comportamiento, la mejor manera es ejecutar setTimeout dentro de setTimeout para emular setInterval .
Para corregir los tiempos de espera entre llamadas setTimeout, puede usar una alternativa de autocorrección a la técnica setInterval de JavaScript .

Serg Hospodarets
fuente
1
¡No sé por qué nadie ha encontrado ningún valor en esta respuesta!
Randika Vishman
9

Yo uso setTimeout.

Aparentemente, la diferencia es que setTimeout llama al método una vez, setInterval lo llama repetidamente.

Aquí hay un buen artículo que explica la diferencia: Tutorial: temporizadores de JavaScript con setTimeout y setInterval

Bravax
fuente
2
Sí, tengo esa diferencia, pero los dos códigos que he proporcionado deberían hacer lo mismo ...
Damovisa
Ummm sí ... hubiera pensado ... pero según dcaunt y su conteo de votos, eso no es exactamente lo que sucede.
Bravax
9

Su código tendrá diferentes intervalos de ejecución, y en algunos proyectos, como los juegos en línea, no es aceptable. Primero, qué debe hacer, para que su código funcione con los mismos intervalos, debe cambiar "myTimeoutFunction" a esto:

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

Después de este cambio, será igual a

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

Pero aún no tendrá un resultado estable, porque JS es de un solo subproceso. Por ahora, si el hilo JS estará ocupado con algo, no podrá ejecutar su función de devolución de llamada, y la ejecución se pospondrá por 2-3 ms. Si tiene 60 ejecuciones por segundo, y cada vez que tenga un retraso aleatorio de 1-3 segundos, no será absolutamente aceptable (después de un minuto será un retraso de alrededor de 7200 ms), y puedo aconsejarle que use algo como esto:

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

Este código garantizará un período de ejecución estable. Incluso el subproceso estará ocupado, y su código se ejecutará después de 1005 ms, la próxima vez tendrá un tiempo de espera de 995 ms, y el resultado será estable.

degr
fuente
7

Hice una prueba simple de setInterval(func, milisec), porque tenía curiosidad por saber qué sucede cuando el consumo de tiempo de función es mayor que la duración del intervalo.

setIntervalserá generalmente programar siguiente iteración justo después del comienzo de la iteración anterior, a menos que la función está todavía en curso . Si es así,setInterval esperará hasta que termine la función. Tan pronto como sucede, la función se vuelve a activar de inmediato: no hay que esperar para la próxima iteración de acuerdo con el cronograma (ya que estaría en condiciones sin una función de tiempo excedido). Tampoco hay una situación con iteraciones paralelas en ejecución.

He probado esto en Chrome v23. Espero que sea una implementación determinista en todos los navegadores modernos.

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

Salida de consola:

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

La waitfunción es solo un ayudante de bloqueo de subprocesos: llamada ajax sincrónica que requiere exactamente 2500 milisegundos de procesamiento en el lado del servidor:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
jwaliszko
fuente
1
"ninguna situación con iteraciones paralelas en ejecución" - sí, esto debería ser imposible. JavaScript del lado del cliente tiene un modelo de ejecución de subprocesos único, por lo que nunca sucede nada (controladores de eventos, etc.) al mismo tiempo. Es por eso que no sucede nada (y el navegador no responde) durante la llamada síncrona ajax.
MrWhite
¿El navegador responde en los pocos ms entre "intervalos"? ¿Se dispararía otro evento si está pendiente? (Gracias por las pruebas por cierto +1)
MrWhite
1
Según MDN, se considera " uso peligroso " si la función podría ejecutarse por más tiempo que el intervalo de tiempo. Se setTimoutprefiere una llamada recursiva .
MrWhite
6

Para verlo un poco diferente: setInterval asegura que se ejecute un código en cada intervalo dado (es decir, 1000 ms, o cuánto especifique) mientras setTimeout establece el tiempo que 'espera hasta' que ejecuta el código. Y dado que se necesitan milisegundos adicionales para ejecutar el código, agrega hasta 1000 ms y, por lo tanto, setTimeout se ejecuta nuevamente en momentos inexactos (más de 1000 ms).

Por ejemplo, los temporizadores / cuenta regresiva no se hacen con setTimeout, se hacen con setInterval, para garantizar que no se demore y el código se ejecute en el intervalo exacto dado.

CatalinBerta
fuente
5

Tanto setInterval como setTimeout devuelven una identificación de temporizador que puede usar para cancelar la ejecución, es decir, antes de que se activen los tiempos de espera. Para cancelar, llame a clearInterval o clearTimeout de esta manera:

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

Además, los tiempos de espera se cancelan automáticamente cuando abandona la página o cierra la ventana del navegador.

Helgi
fuente
4

Puede validar la respuesta de bobince usted mismo cuando ejecuta el siguiente javascript o verifica este 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);
});
Gudradain
fuente
3

Bueno, setTimeout es mejor en una situación, como acabo de aprender. Siempre uso setInterval, que he dejado ejecutar en segundo plano durante más de media hora. Cuando volví a esa pestaña, la presentación de diapositivas (en la que se usó el código) estaba cambiando muy rápidamente, en lugar de cada 5 segundos que debería. De hecho, vuelve a suceder cuando lo pruebo más y no es importante si es culpa del navegador o no, porque con setTimeout esa situación es completamente imposible.

Niño
fuente
Suena como si llamaras setInterval dentro de la función que estabas llamando. Así es como se repite con setTimeout, pero con setInterval en realidad se está creando un bucle completamente nuevo cada vez que se llama.
Stephen R
2

La diferencia es obvia en la consola:

ingrese la descripción de la imagen aquí

testCoder
fuente
2

Simplemente agregue lo que ya se ha dicho, pero la versión setTimeout del código también alcanzará la Maximum call stack sizeque impedirá que funcione. Dado que no hay un caso base para que la función recursiva se detenga, no se puede ejecutar para siempre.

Maaz
fuente
No creo que esto sea cierto. Vea aquí stackoverflow.com/questions/8058612/…
Kevin Wheeler
-1

La diferencia más genérica entre y setInterval (expresión, duración) es que

setTimeout () ejecutará la expresión solo UNA VEZ y después de esa duración especificada.

Sin embargo,

setInterval () ejecutará la expresión en el INFINITE-LOOP después de cada duración especificada.

Anshu Aditya
fuente
-5

Pienso SetIntervaly soy SetTimeoutdiferente. SetIntervalejecuta el bloque de acuerdo con el tiempo establecido, mientras que SetTimeoutejecuta el bloque de código una vez.

Pruebe este conjunto de códigos después de los segundos de cuenta regresiva del tiempo de espera:

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

y luego intenta

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

Puedes ver las diferencias por ti mismo.

Ugbana Chukwujindu Kelvin
fuente
Esto no responde la pregunta. settimeout () puede usarse recursivamente para dar el mismo resultado que setinterval. La pregunta era sobre el rendimiento de estas dos opciones.
Tomás González el