Ir al contenido principal

setTimeout y setInterval

Introducción

JavaScript nos ofrece la capacidad de ejecutar código de forma programada en momentos específicos o en intervalos regulares. Esta funcionalidad es crucial para crear animaciones, actualizar datos periódicamente, implementar temporizadores o simplemente retrasar la ejecución de código. Las funciones setTimeout y setInterval son las herramientas nativas que nos permiten controlar cuándo se ejecuta nuestro código, convirtiéndose en elementos fundamentales para la programación asíncrona básica.

En este artículo, exploraremos cómo funcionan estas funciones, sus diferencias, limitaciones y casos de uso prácticos que encontrarás frecuentemente en el desarrollo web.

La función setTimeout

La función setTimeout permite ejecutar código después de que haya transcurrido un tiempo determinado. Es como decirle a JavaScript: "ejecuta este código, pero espera X milisegundos antes de hacerlo".

Sintaxis básica

setTimeout(funcion, tiempoEnMilisegundos, parametro1, parametro2, ...);

Donde:

  • funcion: Es la función que se ejecutará después del tiempo especificado
  • tiempoEnMilisegundos: El tiempo de espera en milisegundos (1000ms = 1 segundo)
  • parametro1, parametro2, ...: Parámetros opcionales que se pasarán a la función

Ejemplos de uso

Ejemplo básico:

// Muestra un mensaje después de 2 segundos
setTimeout(function() {
    console.log("Han pasado 2 segundos");
}, 2000);

console.log("Este mensaje aparece primero");

Cuando ejecutes este código, verás primero "Este mensaje aparece primero" y después de 2 segundos, verás "Han pasado 2 segundos".

Con función flecha:

// Usando una función flecha
setTimeout(() => {
    console.log("Mensaje con retraso usando función flecha");
}, 1500);

Pasando parámetros:

// Función que recibe parámetros
function saludar(nombre, edad) {
    console.log(`Hola ${nombre}, tienes ${edad} años.`);
}

// Pasamos parámetros a la función
setTimeout(saludar, 3000, "María", 25);

Cancelando un setTimeout

Cuando creamos un setTimeout, este devuelve un identificador único (un número) que podemos usar para cancelar la ejecución programada si es necesario:

// Guardamos el identificador
const temporizador = setTimeout(() => {
    console.log("Este mensaje nunca se mostrará");
}, 5000);

// Cancelamos la ejecución programada
clearTimeout(temporizador);

console.log("Temporizador cancelado");

En este ejemplo, la función programada nunca se ejecutará porque la cancelamos antes de que transcurran los 5 segundos.

La función setInterval

Mientras que setTimeout ejecuta código una sola vez después de un tiempo determinado, setInterval ejecuta código repetidamente con un intervalo de tiempo fijo entre cada ejecución.

Sintaxis básica

setInterval(funcion, intervaloEnMilisegundos, parametro1, parametro2, ...);

Los parámetros son los mismos que en setTimeout.

Ejemplos de uso

Ejemplo básico:

// Muestra un mensaje cada 3 segundos
setInterval(function() {
    console.log("Mensaje repetido cada 3 segundos");
}, 3000);

Crear un contador sencillo:

let contador = 0;

const intervalo = setInterval(() => {
    contador++;
    console.log(`Contador: ${contador}`);
    
    // Paramos después de llegar a 5
    if (contador >= 5) {
        clearInterval(intervalo);
        console.log("Contador finalizado");
    }
}, 1000);

Este código incrementa un contador cada segundo y lo muestra en la consola. Cuando el contador llega a 5, se detiene.

Cancelando un setInterval

Al igual que con setTimeout, setInterval devuelve un identificador que podemos usar para cancelar las ejecuciones futuras:

// Creamos un intervalo que se ejecuta cada segundo
const reloj = setInterval(() => {
    const ahora = new Date();
    console.log(`Hora actual: ${ahora.toLocaleTimeString()}`);
}, 1000);

// Después de 10 segundos, detenemos el reloj
setTimeout(() => {
    clearInterval(reloj);
    console.log("Reloj detenido");
}, 10000);

Este ejemplo crea un reloj que muestra la hora actual cada segundo, y después de 10 segundos lo detiene.

Limitaciones y precisión

Es importante entender que setTimeout y setInterval no garantizan una precisión exacta en el tiempo. Esto se debe a:

  1. Naturaleza de JavaScript: El event loop de JavaScript puede retrasar la ejecución si está ocupado con otras tareas.
  2. Mínimo de tiempo: La mayoría de navegadores tienen un tiempo mínimo de retardo (alrededor de 4ms).
  3. Limitaciones del sistema operativo: El sistema operativo puede influir en la precisión.
// Este ejemplo muestra la imprecisión
console.time("Tiempo real");

setTimeout(() => {
    console.timeEnd("Tiempo real");
    console.log("Debería ser aproximadamente 100ms");
}, 100);

Anidación de timeouts

Una técnica útil es la anidación de timeouts, que permite secuenciar operaciones y es una alternativa a setInterval en algunos casos:

function secuenciaTemporal() {
    console.log("Paso 1");
    
    setTimeout(() => {
        console.log("Paso 2 (después de 1 segundo)");
        
        setTimeout(() => {
            console.log("Paso 3 (después de 2 segundos del inicio)");
        }, 1000);
    }, 1000);
}

secuenciaTemporal();

setTimeout recursivo vs setInterval

Para ejecuciones repetidas, podemos usar setInterval o un setTimeout recursivo:

// Con setInterval (intervalos fijos)
let contadorInterval = 0;
const miIntervalo = setInterval(() => {
    contadorInterval++;
    console.log(`setInterval: ${contadorInterval}`);
    if (contadorInterval >= 3) clearInterval(miIntervalo);
}, 1000);

// Con setTimeout recursivo (más flexible)
let contadorTimeout = 0;
function ejecutarRecursivo() {
    contadorTimeout++;
    console.log(`setTimeout recursivo: ${contadorTimeout}`);
    
    if (contadorTimeout < 3) {
        setTimeout(ejecutarRecursivo, 1000);
    }
}
setTimeout(ejecutarRecursivo, 1000);

La ventaja del setTimeout recursivo es que el intervalo entre ejecuciones puede ajustarse dinámicamente o incluso puede depender del resultado de la ejecución anterior.

Buenas prácticas

  1. Siempre limpiar los temporizadores cuando ya no sean necesarios, especialmente en componentes web que pueden desmontarse.
// En un contexto de aplicación web
function iniciarActualizacionDatos() {
    const intervaloActualizacion = setInterval(actualizarDatos, 5000);
    
    // Guardamos referencia para limpieza posterior
    return intervaloActualizacion;
}

function detenerActualizacion(intervaloID) {
    clearInterval(intervaloID);
    console.log("Actualización detenida");
}

// Uso
const miIntervalo = iniciarActualizacionDatos();

// Cuando ya no necesitamos las actualizaciones
detenerActualizacion(miIntervalo);
  1. Evitar intervalos muy cortos (menos de 16ms) si no es absolutamente necesario.

  2. Usar requestAnimationFrame en lugar de setTimeout/setInterval para animaciones (tiene mejor rendimiento y sincronización con el navegador).

// Mejor para animaciones
function animar() {
    // Código de animación...
    
    // Programar siguiente cuadro
    requestAnimationFrame(animar);
}

// Iniciar animación
requestAnimationFrame(animar);

Alternativas modernas

En el desarrollo web moderno, existen alternativas que pueden ser más adecuadas en ciertos casos:

  1. Promesas y async/await para secuencias asíncronas más complejas.
  2. Web Workers para tareas pesadas que necesitan ejecutarse periódicamente sin bloquear la interfaz.
  3. API de Notificaciones para recordatorios al usuario incluso cuando el navegador está en segundo plano.

Ejemplo práctico: Creación de un temporizador de cuenta atrás

Vamos a crear un ejemplo práctico: un temporizador de cuenta atrás de 10 segundos que podemos iniciar, pausar y reiniciar:

// Función para crear un temporizador
function crearTemporizador(duracionInicial) {
    let duracion = duracionInicial;
    let intervaloID = null;
    let enPausa = true;
    
    // Mostrar tiempo inicial
    console.log(`Temporizador: ${duracion} segundos`);
    
    // Métodos del temporizador
    return {
        iniciar: function() {
            if (enPausa) {
                enPausa = false;
                console.log("Temporizador iniciado");
                
                intervaloID = setInterval(() => {
                    duracion--;
                    console.log(`Tiempo restante: ${duracion} segundos`);
                    
                    if (duracion <= 0) {
                        console.log("¡Tiempo agotado!");
                        this.detener();
                    }
                }, 1000);
            }
        },
        
        pausar: function() {
            if (!enPausa) {
                clearInterval(intervaloID);
                intervaloID = null;
                enPausa = true;
                console.log("Temporizador pausado");
            }
        },
        
        reiniciar: function() {
            this.pausar();
            duracion = duracionInicial;
            console.log(`Temporizador reiniciado: ${duracion} segundos`);
        }
    };
}

// Crear un temporizador de 10 segundos
const miTemporizador = crearTemporizador(10);

// Para probarlo en la consola:
// miTemporizador.iniciar();
// miTemporizador.pausar();
// miTemporizador.reiniciar();

Este ejemplo muestra cómo podemos crear una aplicación más compleja utilizando setInterval y clearInterval en conjunto con técnicas de clausuras (closures) en JavaScript.

Resumen

Las funciones setTimeout y setInterval son herramientas fundamentales para trabajar con código asíncrono en JavaScript. setTimeout permite ejecutar código después de un retraso específico, mientras que setInterval ejecuta código repetidamente con un intervalo regular.

Aunque tienen sus limitaciones en cuanto a precisión, son extremadamente útiles para una amplia gama de aplicaciones: desde simples retrasos y animaciones hasta actualizaciones periódicas de datos en aplicaciones web. Recuerda siempre guardar los identificadores retornados por estas funciones para poder cancelarlas cuando ya no sean necesarias, evitando así fugas de memoria y comportamientos inesperados.

En los próximos artículos, profundizaremos en técnicas más avanzadas de programación asíncrona, como las promesas, que complementan y expanden lo que hemos aprendido sobre estos temporizadores básicos.