• Sobre mí
  • Proyectos
  • Contacto
  • Blog

Apasionado por el desarrollo web y el diseño de interfaces intuitivas.

Cada error es un paso. Cada línea, un aprendizaje.

📍   Salou, Tarragona, España ✉️   [email protected] 📞   +34 641932611

Curriculum

Ver mi curriculum completo

Mapa del sitio

  • Inicio
  • Blog
  • Proyectos
  • Sobre mi
  • Mi misión
  • Sitemap

Contácto

  • Página de contácto
  • LinkedIn
  • GitHub

2026 Frankuxui - Todos los derechos reservados

  • Términos y condiciones
  • Política de privacidad
  • Política de cookies
Imagen de unsplash creada por Peter Burdon
Imagen de unsplash creada por Peter Burdon
  • JavaScript

Articulo publicado el 13 de julio de 2026

Por Frank Esteban Isdray Junco

Debounce y Throttle: Controla la frecuencia de ejecución de funciones

Optimiza el rendimiento de tu aplicación limitando cuántas veces se ejecutan listeners de eventos y funciones costosas

Qué son Debounce y Throttle

Debounce y Throttle son técnicas de programación que controlan la frecuencia con la que se ejecuta una función. Ambas resuelven el mismo problema: limitar el número de veces que se llama a una función costosa o que genera muchas ejecuciones innecesarias, pero cada una toma un enfoque diferente.

Cuando trabajas con eventos como scroll, resize, mousemove o búsqueda en tiempo real, el navegador puede dispararlos cientos de veces por segundo. Sin debounce o throttle, tu aplicación puede ralentizarse significativamente porque estás ejecutando lógica cara (validaciones, peticiones HTTP, cálculos DOM) demasiadas veces.

El problema sin Debounce o Throttle

Imagina una búsqueda en tiempo real donde cada tecla que presiona el usuario dispara una petición al servidor:

javascript
// Sin control - ineficiente
const input = document.getElementById("search");

input.addEventListener("input", (e) => {
  const query = e.target.value;

  // Esto se ejecuta en CADA tecla presionada
  fetch(`/api/search?q=${query}`)
    .then((res) => res.json())
    .then((data) => console.log(data));
});

Si un usuario escribe "javascript" (10 caracteres), esto dispara 10 peticiones HTTP al servidor. Eso es ineficiente, caro y puede generar problemas de concurrencia en tu backend.

Diferencia entre Debounce y Throttle

Aunque ambas técnicas limitan ejecuciones, lo hacen de manera distinta:

Debounce: Espera a que pare la actividad

Debounce retrasa la ejecución de una función hasta que ha pasado un tiempo específico sin que se llame. Es ideal para acciones que ocurren después de que el usuario "termina" de hacer algo.

Caso de uso: Campo de búsqueda, validación de formulario, guardado automático.

javascript
// Debounce: espera 300ms sin actividad antes de ejecutar
function debounce(func, delay) {
  let timeoutId;

  return function (...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      func(...args);
    }, delay);
  };
}

const input = document.getElementById("search");
const debouncedSearch = debounce((e) => {
  const query = e.target.value;
  fetch(`/api/search?q=${query}`)
    .then((res) => res.json())
    .then((data) => console.log(data));
}, 300);

input.addEventListener("input", debouncedSearch);

En este ejemplo, si el usuario escribe "javascript" (10 caracteres) a velocidad normal, solo se dispara 1 petición 300ms después de que deja de escribir.

Throttle: Ejecuta a intervalos regulares

Throttle ejecuta una función como máximo una vez cada X milisegundos, independientemente de cuántas veces se dispare el evento. Es ideal para acciones que necesitan ejecutarse regularmente pero con un límite máximo.

Caso de uso: Scroll infinito, redimensionamiento de ventana, tracking de mouse.

javascript
// Throttle: ejecuta máximo cada 300ms
function throttle(func, delay) {
  let lastCall = 0;

  return function (...args) {
    const now = Date.now();

    if (now - lastCall >= delay) {
      func(...args);
      lastCall = now;
    }
  };
}

window.addEventListener(
  "scroll",
  throttle(() => {
    console.log("Scroll detectado");
    // Lógica costosa
  }, 300)
);

En este ejemplo, aunque el usuario haga scroll rápidamente (disparando el evento cientos de veces), la función se ejecuta máximo cada 300ms.

Cuándo usar Debounce

Usa debounce cuando necesites ejecutar una función después de que la actividad del usuario se haya detenido:

Búsqueda en tiempo real

javascript
const searchInput = document.getElementById("search");

const debouncedSearch = debounce((e) => {
  const query = e.target.value;

  if (query.length === 0) {
    clearResults();
    return;
  }

  searchAPI(query).then((results) => displayResults(results));
}, 500);

searchInput.addEventListener("input", debouncedSearch);

Validación de formulario

javascript
const emailInput = document.getElementById("email");

const debouncedValidate = debounce((e) => {
  const email = e.target.value;

  if (!isValidEmail(email)) {
    showError("Email inválido");
    return;
  }

  checkEmailExists(email).then((exists) => {
    if (exists) {
      showError("Email ya registrado");
    } else {
      showSuccess("Email disponible");
    }
  });
}, 400);

emailInput.addEventListener("blur", debouncedValidate);
emailInput.addEventListener("input", debouncedValidate);

Guardado automático

javascript
const editor = document.getElementById("editor");

const debouncedSave = debounce(() => {
  const content = editor.value;
  saveToServer(content).then(() => {
    showNotification("Guardado correctamente");
  });
}, 2000);

editor.addEventListener("input", debouncedSave);

Cuándo usar Throttle

Usa throttle cuando necesites limitar la frecuencia de una función que se ejecuta continuamente durante la actividad del usuario:

Detección de scroll

javascript
const throttledScroll = throttle(() => {
  const scrollTop = window.scrollY;

  if (scrollTop > 100) {
    showBackToTopButton();
  } else {
    hideBackToTopButton();
  }
}, 100);

window.addEventListener("scroll", throttledScroll);

Tracking de mouse para analíticas

javascript
const throttledTracking = throttle((e) => {
  const mouseX = e.clientX;
  const mouseY = e.clientY;

  // Registrar posición en servidor (máximo cada 100ms)
  trackMousePosition(mouseX, mouseY);
}, 100);

document.addEventListener("mousemove", throttledTracking);

Redimensionamiento de ventana

javascript
const throttledResize = throttle(() => {
  const width = window.innerWidth;
  const height = window.innerHeight;

  // Recalcular layout (máximo cada 250ms)
  recalculateLayout(width, height);
}, 250);

window.addEventListener("resize", throttledResize);

Implementaciones avanzadas

Debounce con opción de ejecución inmediata

A veces necesitas que la función se ejecute inmediatamente en la primera llamada, y luego espere a que pare la actividad:

javascript
function debounceWithLeading(func, delay) {
  let timeoutId;
  let lastCall = 0;

  return function (...args) {
    const now = Date.now();
    const isFirstCall = lastCall === 0;

    // Ejecutar inmediatamente en primera llamada
    if (isFirstCall) {
      func(...args);
      lastCall = now;
    }

    clearTimeout(timeoutId);

    // Ejecutar de nuevo al final si hay actividad
    timeoutId = setTimeout(() => {
      if (now - lastCall >= delay) {
        func(...args);
        lastCall = now;
      }
    }, delay);
  };
}

Throttle con opción de trailing

A veces quieres asegurar que se ejecute una última vez después de que la actividad termina:

javascript
function throttleWithTrailing(func, delay) {
  let lastCall = 0;
  let timeoutId;

  return function (...args) {
    const now = Date.now();

    if (now - lastCall >= delay) {
      func(...args);
      lastCall = now;
    }

    clearTimeout(timeoutId);

    // Ejecutar una última vez al final
    timeoutId = setTimeout(() => {
      func(...args);
      lastCall = now;
    }, delay);
  };
}

Performance: Comparación visual

Para un evento que se dispara 100 veces en 1 segundo:

  • Sin control: 100 ejecuciones
  • Con Debounce (300ms): 1-2 ejecuciones (después de la actividad)
  • Con Throttle (300ms): ~3-4 ejecuciones (distribuidas regularmente)

Casos reales de impacto

Búsqueda sin debounce: 50 peticiones HTTP por búsqueda Búsqueda con debounce (500ms): 1 petición por búsqueda

Eso es 50x menos carga en el servidor.

Errores comunes

Error 1: Usar Debounce para Scroll

javascript
// ❌ INCORRECTO: Debounce en scroll
window.addEventListener(
  "scroll",
  debounce(() => {
    loadMoreContent();
  }, 500)
);

// ✅ CORRECTO: Throttle en scroll
window.addEventListener(
  "scroll",
  throttle(() => {
    loadMoreContent();
  }, 300)
);

El scroll infinito necesita ejecutarse regularmente mientras se hace scroll, no al final.

Error 2: Recrear la función en cada render

javascript
// ❌ INCORRECTO en React
function SearchComponent() {
  const handleSearch = debounce((query) => {
    searchAPI(query);
  }, 500);

  return <input onChange={handleSearch} />;
}

// ✅ CORRECTO: Memoizar la función debounceada
function SearchComponent() {
  const handleSearch = useMemo(
    () =>
      debounce((query) => {
        searchAPI(query);
      }, 500),
    []
  );

  return <input onChange={handleSearch} />;
}

Error 3: No limpiar timeouts

Si el componente se desmonta, los timeouts quedan pendientes:

javascript
// ✅ CORRECTO: Limpiar en unmount
function useDebouncedSearch(callback, delay) {
  const debouncedRef = useRef();

  useEffect(() => {
    debouncedRef.current = debounce(callback, delay);

    return () => {
      // Limpiar timeout al desmontar
      debouncedRef.current.cancel?.();
    };
  }, [callback, delay]);

  return debouncedRef.current;
}

Librerías recomendadas

Para proyectos grandes, considera usar librerías bien mantenidas:

  • Lodash: _.debounce() y _.throttle()
  • date-fns: Utilidades para funciones temporizadas
  • Hooks personalizados: En React, usa useDebouncedValue o useThrottledCallback

Conclusión

Debounce es para esperar a que la actividad termine; Throttle es para limitar la frecuencia regular.

Dominar estas técnicas es esencial para construir aplicaciones frontend rápidas y responsivas. Úsalas estratégicamente para mejorar el rendimiento, reducir la carga del servidor y proporcionar una mejor experiencia de usuario.

En este artículo

  1. Qué son Debounce y Throttle
  2. El problema sin Debounce o Throttle
  3. Diferencia entre Debounce y Throttle
  4. Debounce: Espera a que pare la actividad
  5. Throttle: Ejecuta a intervalos regulares
  6. Cuándo usar Debounce
  7. Búsqueda en tiempo real
  8. Validación de formulario
  9. Guardado automático
  10. Cuándo usar Throttle
  11. Detección de scroll
  12. Tracking de mouse para analíticas
  13. Redimensionamiento de ventana
  14. Implementaciones avanzadas
  15. Debounce con opción de ejecución inmediata
  16. Throttle con opción de trailing
  17. Performance: Comparación visual
  18. Casos reales de impacto
  19. Errores comunes
  20. Error 1: Usar Debounce para Scroll
  21. Error 2: Recrear la función en cada render
  22. Error 3: No limpiar timeouts
  23. Librerías recomendadas
  24. Conclusión

Articulos relacionados

Estos articulos pueden interesarte si te gusto este articulo.

Imagen de unsplash creada por Frans Ruiter
Imagen del articulo Fotografía de Unsplash
13 de julio de 2026
JavaScript

Event Delegation en JavaScript Vanilla: Optimiza tu DOM

Cómo reducir listeners y mejorar el rendimiento usando bubbling de eventos

Imagen de unsplash creada por Benjamin Chambon
Imagen del articulo Fotografía de Unsplash
13 de julio de 2026
JavaScript

Event Delegation: Optimiza tus listeners en JavaScript

Maneja eventos en múltiples elementos con un único listener y mejora el rendimiento de tu aplicación

Fotografía de unsplash creada por Carter Obasohan
Imagen del articulo Los atributos data-* permiten enlazar datos y comportamiento en HTML
8 de julio de 2026
HTML
·JavaScript

Atributos data-* en HTML: Almacena datos personalizados en tu DOM

Aprende a usar los atributos data-* para guardar información en elementos HTML y accederla desde JavaScript de forma segura y semántica