Debouncing input en Laravel con Alpine

El debouncing es una técnica que se asegura de que una función x() solo se llame una vez durante un intervalo de tiempo determinado.

Debouncing input en Laravel con Alpine
Photo by Kai Pilger / Unsplash

Siguiendo nuestra serie de AlpineJS, una de las maravillas que trae implementadas es una función de debouncing. Alpine no es la primera librería que tiene esta funcionalidad, pero si ya lo estamos usando en el proyecto es un plus para no cargar más librerías. Otros ejemplos de debounce:

¿Qué es el debounce?

Imagínate que tenemos el siguiente input que, mientras escribimos, queremos que se realice una petición a la API para ver los resultados en tiempo real:

<input type="search" x-model="search" x-on:keyup="liveSearch()" />

Cada vez que añadamos una letra, se llamará a la función liveSearch(), que lanzará una petición API. Esto trae un par de problemas:

  • Si escribimos 20 letras, vamos a hacer 20 peticiones API. Además, si escribimos rápido, 19 de esas peticiones no habrán servido probablemente para nada
  • Las peticiones API son asíncronas. Esto quiere decir que el sistema lanzará 20 peticiones, pero no podemos garantizar que el orden en el que las recibimos sea el orden en el que las enviamos → Podemos mostrar al usuario resultados erróneos

El debounce viene al rescate en estos casos 🫡

El debouncing es una técnica que se asegura de que una función x() solo  se llame una vez durante un intervalo de tiempo determinado.

Su implementación viene a ser algo así:

function debounce(func, timeout = 300){
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => { func.apply(this, args); }, timeout);
  };
}

En nuestro caso, para la búsqueda, implicaría que la función liveSearch() se llamaría 20 veces, pero no se llamaría hasta que el usuario esté, por ejemplo, 200ms sin escribir una letra. De esta forma, reducimos drásticamente el número de llamadas API.

Cómo usar debounce con Alpine

Como pasa casi siempre con AlpineJS, es muy fácil :-) Solamente tenemos que indicar el debouncing en el listener (250ms por defecto):

<input type="search" x-model="search" x-on:keyup.debounce="liveSearch()" />

Además, también podemos indicarle la duración:

<input type="search" x-model="search" x-on:keyup.debounce.300ms="liveSearch()" />

Por último, también podemos usar el debounce directamente en nuestro código JS:

import Alpine from 'alpinejs';

...

const liveSearch = () => {
    ...
};
const debouncedFunction = Alpine.debounce(liveSearch, 300);