Saltar al contenido
temporizadores.js · devschool

setTimeout y setInterval en JavaScript

Lección 30 de 38 · 4 min de lectura · Actualizado el

En esta lección
  1. setTimeout: una vez, más tarde
  2. setInterval: repetir cada cierto tiempo
  3. Los tiempos no son exactos
  4. Debounce: esperar a que el usuario pare
  5. Esperar dentro de una función async
  6. Animaciones: requestAnimationFrame

JavaScript no tiene una instrucción para “esperar X segundos” y seguir (como el sleep de otros lenguajes): bloquearía toda la página. En su lugar, le pides al navegador que ejecute una función más tarde.

setTimeout: una vez, más tarde

setTimeout(() => {
  console.log("Han pasado 2 segundos");
}, 2000);
  • Primer argumento: la función que se ejecutará.
  • Segundo argumento: el retraso en milisegundos (1000 ms = 1 segundo).

Lo importante: el programa no se detiene. setTimeout programa la función y el código sigue ejecutándose inmediatamente. La función se ejecutará cuando pase el tiempo y el navegador esté libre. Fíjate en el orden de los mensajes del ejemplo de abajo.

Si pasas una función con nombre, recuerda: sin paréntesis.

function avisar() { console.log("¡Tiempo!"); }
setTimeout(avisar, 3000);     // ✓
setTimeout(avisar(), 3000);   // ✗ ejecuta avisar YA y programa su resultado (undefined)

Cancelar

setTimeout devuelve un identificador. Con él puedes cancelar la ejecución antes de que ocurra:

const aviso = setTimeout(mostrarAyuda, 5000);
// si el usuario hace algo antes de 5 segundos:
clearTimeout(aviso);

setInterval: repetir cada cierto tiempo

const reloj = setInterval(() => {
  document.querySelector("#hora").textContent =
    new Date().toLocaleTimeString("es-ES");
}, 1000);

La función se ejecuta cada 1000 ms hasta que la pares:

clearInterval(reloj);

Para siempre los intervalos cuando ya no hagan falta. Un intervalo olvidado sigue consumiendo recursos, y si creas uno nuevo cada vez que se pulsa un botón, acabarás con varios ejecutándose a la vez (el típico reloj que de repente “va el doble de rápido”).

Ejemplo: consultar datos periódicamente

Un uso clásico es pedir datos nuevos a un servidor cada cierto tiempo (cotizaciones, un marcador deportivo, mensajes nuevos):

async function actualizarCotizacion() {
  const respuesta = await fetch("/api/cotizacion/EURUSD");
  const datos = await respuesta.json();
  document.querySelector("#cambio").textContent = datos.valor;
}

actualizarCotizacion();                        // una vez al cargar
setInterval(actualizarCotizacion, 60_000);     // y luego cada minuto

(El _ en 60_000 es solo un separador para leer mejor el número.)

Los tiempos no son exactos

El retraso es un mínimo, no una garantía. Si el navegador está ocupado ejecutando otra cosa, la función esperará. Además, en las pestañas que no están visibles, los navegadores ralentizan los temporizadores para ahorrar batería.

Consecuencia: no cuentes el tiempo sumando intervalos. Para un cronómetro o una cuenta atrás, guarda la hora de inicio y calcula la diferencia con la hora actual en cada tic:

const inicio = Date.now();
setInterval(() => {
  const segundos = Math.floor((Date.now() - inicio) / 1000);
  marcador.textContent = segundos;
}, 250);

Debounce: esperar a que el usuario pare

Imagina un buscador que consulta al servidor mientras escribes. Si lanzas una petición con cada tecla, “javascript” serían 10 peticiones. La técnica del debounce espera a que el usuario deje de escribir un momento:

let temporizador;

buscador.addEventListener("input", () => {
  clearTimeout(temporizador);                   // cancela la búsqueda anterior
  temporizador = setTimeout(() => {
    buscar(buscador.value);                     // solo se ejecuta si pasan 300 ms sin teclear
  }, 300);
});

Cada tecla cancela el temporizador anterior y crea uno nuevo. Solo cuando pasan 300 ms sin escribir se ejecuta la búsqueda.

Esperar dentro de una función async

Con promesas puedes crear una pequeña función de espera que se usa con await:

const esperar = (ms) => new Promise((resolver) => setTimeout(resolver, ms));

async function mostrarPasos() {
  console.log("Paso 1");
  await esperar(1000);
  console.log("Paso 2");
}

Aquí sí parece que el código “se detiene”, pero solo se pausa esa función; el resto de la página sigue funcionando.

Animaciones: requestAnimationFrame

Para animaciones con JavaScript (mover algo en un <canvas>, un juego), no uses setInterval. Usa requestAnimationFrame, que se sincroniza con el refresco de la pantalla (normalmente 60 veces por segundo) y se pausa solo cuando la pestaña no se ve:

function animar() {
  // actualizar posiciones y dibujar...
  requestAnimationFrame(animar);
}
requestAnimationFrame(animar);

Para animaciones de la interfaz (botones, menús), casi siempre es mejor usar transiciones de CSS.

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

temporizadores.js
Consola

Pon a prueba lo que has aprendido

[JavaScript] ¿En qué orden salen los mensajes?
console.log("A");
setTimeout(() => console.log("B"), 0);
console.log("C");

[JavaScript] ¿Cómo se detiene un intervalo creado con const id = setInterval(...)?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.