Debounce oder Throttle?

Beide begrenzen, wie oft ein Handler läuft. Die Wahl hängt davon ab, was der Nutzer sehen soll, solange noch Events eintreffen.

Manche Events feuern viel öfter als nötig: input bei jedem Tastendruck, scroll und pointermove Dutzende Male pro Sekunde. Debouncing und Throttling reduzieren beide die Zahl der Aufrufe, verhalten sich aber unterschiedlich, solange noch Events eintreffen.

Debounce: warten, bis Ruhe ist

Eine Funktion mit Debounce läuft erst, wenn für eine bestimmte Zeit keine Events mehr gekommen sind. Das passt zu Arbeit, die nur für den Endwert sinnvoll ist, etwa eine Suchanfrage abschicken oder einen Entwurf speichern.

function debounce(fn, wait) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), wait);
  };
}

input.addEventListener('input', debounce(search, 250));

Throttle: weitermachen, aber langsamer

Eine Funktion mit Throttle läuft höchstens einmal pro Intervall, solange die Events anhalten. Das passt, wenn der Nutzer schon während der Interaktion eine Veränderung sehen soll, zum Beispiel eine Positionsanzeige beim Ziehen.

function throttle(fn, wait) {
  let last = 0;
  let timer;
  return function (...args) {
    const remaining = wait - (Date.now() - last);
    clearTimeout(timer);
    if (remaining <= 0) {
      last = Date.now();
      fn.apply(this, args);
    } else {
      timer = setTimeout(() => {
        last = Date.now();
        fn.apply(this, args);
      }, remaining);
    }
  };
}

Diese Variante ruft die Funktion sofort auf, danach höchstens alle wait Millisekunden und am Ende noch einmal, damit der letzte Wert nie verloren geht.

Für alles Visuelle: die Bildrate

Aktualisiert der Handler nur, was auf dem Bildschirm steht, ist das natürliche Intervall ein Frame. requestAnimationFrame liefert genau das, ohne dass man eine Zahl wählen muss:

let queued = false;
window.addEventListener('scroll', () => {
  if (queued) return;
  queued = true;
  requestAnimationFrame(() => {
    queued = false;
    updateProgressBar(window.scrollY);
  });
}, { passive: true });

Als Faustregel: Debounce für das Ergebnis, Throttle für Rückmeldung und requestAnimationFrame für Pixel.

← Alle Notizen