Día 13 de 24: debounce
13 de diciembre de 2025

Día 13 de 24: debounce

Las 24 funciones para navidad

Por Asdrúbal Chirinos

En esta serie hemos venido construyendo pequeñas funciones pensadas para el día a día, utilidades que resuelven problemas reales sin depender de frameworks ni soluciones pesadas. En el día anterior hablamos de control y precisión en el manejo del tiempo. Hoy damos un paso más y nos enfocamos en algo clave cuando trabajamos con interfaces y eventos frecuentes: saber cuándo ejecutar una función, no solo cómo hacerlo.

Día 12 de 24: endOfDay Las 24 funciones antes de navidad 12 de diciembre de 2025
Día 12 de 24: endOfDay

debounce

La función debounce resuelve un problema muy común en aplicaciones web y scripts interactivos: evitar que una función se ejecute demasiadas veces en un corto período de tiempo.

Eventos como scroll, resize o input pueden dispararse decenas o cientos de veces por segundo. Ejecutar lógica pesada en cada uno de esos disparos suele ser innecesario y costoso. debounce permite retrasar la ejecución hasta que el usuario haya dejado de generar eventos durante un tiempo determinado.

Esto es especialmente útil en proyectos reales para:

  • Validaciones de formularios en tiempo real.
  • Búsquedas con autocompletado.
  • Recalcular layouts al redimensionar la ventana.
  • Evitar llamadas innecesarias a APIs.

A diferencia de soluciones nativas como setTimeout manual en cada uso, esta implementación encapsula el patrón completo, agrega validaciones y expone una API clara, incluyendo soporte para ejecución inmediata y cancelación.

Código de la función

/**
 * Debounce: retrasa la ejecución de una función hasta que hayan pasado
 * `delay` milisegundos desde la última invocación.
 * Útil para eventos de alta frecuencia (scroll, resize, input).
 * @param {Function} func Función a ejecutar.
 * @param {number} delay Tiempo de espera en ms.
 * @param {object} [options]
 * @param {boolean} [options.leading=false] Si true, ejecuta inmediatamente en la primera llamada.
 * @returns {Function} Función debounced con método .cancel() para cancelar ejecuciones pendientes.
 */
export function debounce(func, delay, options = {}) {
  if (typeof func !== 'function') throw new Error('func debe ser una función');
  if (typeof delay !== 'number' || delay < 0) throw new Error('delay debe ser un número >= 0');
  
  const { leading = false } = options;
  let timeoutId = null;
  let lastCallTime = 0;
  
  const debounced = function (...args) {
    const now = Date.now();
    const isFirstCall = lastCallTime === 0;
    
    clearTimeout(timeoutId);
    lastCallTime = now;
    
    if (leading && isFirstCall) {
      func.apply(this, args);
    } else {
      timeoutId = setTimeout(() => {
        func.apply(this, args);
        lastCallTime = 0;
      }, delay);
    }
  };
  
  debounced.cancel = function () {
    clearTimeout(timeoutId);
    timeoutId = null;
    lastCallTime = 0;
  };
  
  return debounced;
}

Cómo usarla

Caso básico

Ejecutar una función solo cuando el usuario deja de escribir durante 300 ms:

const onInput = debounce((value) => {
  console.log('Buscar:', value);
}, 300);

input.addEventListener('input', (e) => {
  onInput(e.target.value);
});

Ejecución inmediata (leading)

Útil cuando quieres reaccionar al primer evento y luego esperar:

const onResize = debounce(() => {
  console.log('Resize inicial');
}, 500, { leading: true });

window.addEventListener('resize', onResize);

Aquí la función se ejecuta de inmediato en el primer resize y luego se bloquea hasta que pase el tiempo indicado sin nuevos eventos.

Cancelar una ejecución pendiente

En algunos flujos es importante abortar la acción programada:

const saveDraft = debounce(() => {
  console.log('Guardando borrador');
}, 1000);

// Cancelar si el usuario navega a otra vista
saveDraft.cancel();

Con debounce añadimos una pieza fundamental para construir interfaces más eficientes y predecibles. Es una función pequeña, pero con un impacto enorme en rendimiento y experiencia de usuario. Mañana seguiremos sumando utilidades que, combinadas, forman una caja de herramientas sólida para proyectos reales y código que se siente bien usar.

Compartir:

¿Te gustó este artículo? Apoya mi trabajo y ayúdame a seguir creando contenido.

Cómprame un café