Pular para o conteúdo

Debounce em JavaScript: o snippet pequeno que salva busca, autocomplete e API

Tem um bug de experiência que aparece em muito projeto: o usuário digita em um campo de busca e, a cada tecla, a aplicação dispara uma nova requisição.

Digitou “r”? API.

Digitou “re”? API.

Digitou “rea”? API.

Digitou “react”? Parabéns, você acabou de fazer cinco chamadas para descobrir uma palavra.

É aqui que entra o debounce.

O problema

Em interfaces com busca, autocomplete, filtros ou validações em tempo real, eventos podem disparar muitas vezes em poucos segundos. Isso pode gerar chamadas desnecessárias para API, processamento repetido e uma experiência menos fluida.

O problema não é o usuário digitar rápido. O problema é a aplicação reagir como se cada tecla fosse uma decisão final.

O que é debounce?

Debounce é uma técnica simples: em vez de executar uma função imediatamente, você espera um pequeno intervalo. Se a função for chamada de novo antes desse tempo terminar, o contador reinicia.

Na prática, isso permite esperar o usuário “parar de digitar” antes de buscar alguma coisa.

Debounce não é sobre deixar tudo mais lento. É sobre evitar trabalho inútil.

O snippet

function debounce(callback, delay = 500) {
  let timeoutId;

  return function (...args) {
    clearTimeout(timeoutId);

    timeoutId = setTimeout(() => {
      callback.apply(this, args);
    }, delay);
  };
}

Como esse código funciona?

A função debounce recebe um callback e um tempo de espera em milissegundos. Ela retorna uma nova função que controla quando o callback original será executado.

Sempre que essa nova função é chamada, o timeout anterior é cancelado com clearTimeout. Em seguida, um novo timeout é criado com setTimeout.

Se nenhuma nova chamada acontecer dentro do intervalo definido, o callback finalmente roda.

Exemplo prático com campo de busca

<input id="search" type="search" placeholder="Buscar posts..." />
const input = document.querySelector("#search");

async function searchPosts(query) {
  if (!query.trim()) return;

  const response = await fetch(`/api/posts?q=${encodeURIComponent(query)}`);
  const posts = await response.json();

  console.log(posts);
}

const debouncedSearch = debounce((event) => {
  searchPosts(event.target.value);
}, 600);

input.addEventListener("input", debouncedSearch);

Nesse exemplo, a função searchPosts só roda 600ms depois da última digitação. Se o usuário continuar digitando, o timeout anterior é cancelado e um novo começa.

Quando usar debounce?

Debounce é especialmente útil em situações como:

  • campos de busca;
  • autocomplete;
  • filtros de produto;
  • validação de formulário;
  • eventos de resize da janela;
  • scroll com cálculos pesados;
  • requisições para API disparadas por interação do usuário.

Por que isso melhora a experiência?

Se cada tecla chama uma API, você está pedindo para o backend acompanhar o ritmo do teclado do usuário. Com debounce, você troca ansiedade por intenção.

A aplicação espera um pouquinho, entende melhor o que a pessoa quer e só então faz a chamada.

Às vezes, performance começa com uma função de dez linhas.

Fontes

"Loop"

"Loop"

Lucas “Loop” Torres é desenvolvedor web e escreve sobre JavaScript, TypeScript, PHP e as pequenas decisões que fazem um projeto sair do “funciona na minha máquina” para algo minimamente decente. Ganhou o apelido na faculdade depois de alguns loops infinitos memoráveis e, desde então, tenta transformar bugs, ferramentas e tendências da web em conteúdo útil para quem também vive entre commits, café e deploys de última hora.View Author posts