Przejdź do głównej treści
Grafika przedstawia ukryty obrazek

Throttling vs Debouncing w JavaScript – kiedy i jak je stosować?

Throttling vs Debouncing w JavaScript – kiedy i jak je stosować?

W świecie nowoczesnych aplikacji internetowych wydajność i responsywność interfejsu użytkownika są kluczowe. Wiele zdarzeń w przeglądarce, takich jak przewijanie (scroll), zmiana rozmiaru (resize) czy ruch myszy (mousemove), może być wywoływanych dziesiątki lub setki razy na sekundę. Jeśli za każdym razem uruchamiamy kosztowną funkcję, bardzo szybko możemy doprowadzić do problemów z wydajnością. Tu z pomocą przychodzą dwie techniki: throttling i debouncing.

Czym są throttling i debouncing?

Throttling (dławienie)

Throttling ogranicza częstotliwość wywoływania funkcji. Gdy użytkownik wyzwala dane zdarzenie wielokrotnie, throttling sprawia, że funkcja wykonuje się maksymalnie raz na określony przedział czasu, np. co 200 ms – nawet jeśli zdarzenie występuje częściej.

Idealny do sytuacji, w których chcemy aktualizować coś regularnie, ale nie za często.

Przykłady zastosowania:

  • Śledzenie pozycji myszy
  • Automatyczne zapisywanie danych
  • Reagowanie na scroll (np. w nieskończonym scrollowaniu)

Debouncing (opóźnianie)

Debouncing działa inaczej – funkcja nie wykonuje się natychmiast, lecz czeka, aż zdarzenia ustaną. Jeśli zdarzenie powtarza się, timer jest resetowany. Funkcja zostanie wykonana tylko po upływie określonego czasu od ostatniego wywołania.

Idealny do sytuacji, w których chcemy wykonać operację dopiero po zakończeniu serii działań użytkownika.

Przykłady zastosowania:

  • Wyszukiwanie podczas wpisywania (np. w polu input)
  • Walidacja formularzy
  • Dynamiczne filtrowanie danych

Porównanie: Throttle vs Debounce

Cecha Throttling Debouncing
Kiedy się wykonuje Regularnie, co X ms Po X ms od ostatniego wywołania
Częstotliwość wykonania Maksymalnie raz na X ms Tylko raz po zakończeniu serii wywołań
Typowe zastosowania Scroll, resize, śledzenie myszy Input search, autosave po edycji
Przykład z życia Kontroler klimatyzacji co 5 minut Alarm, który uruchamia się po bezruchu

Przykłady kodu

Funkcja throttle

function throttle(func, limit) {
  let lastFunc;
  let lastRan;

  return function(...args) {
    const context = this;
    if (!lastRan) {
      func.apply(context, args);
      lastRan = Date.now();
    } else {
      clearTimeout(lastFunc);
      lastFunc = setTimeout(function() {
        if ((Date.now() - lastRan) >= limit) {
          func.apply(context, args);
          lastRan = Date.now();
        }
      }, limit - (Date.now() - lastRan));
    }
  };
}

Użycie:

const logScroll = () => console.log('Scrolling...');
window.addEventListener('scroll', throttle(logScroll, 300));

Funkcja debounce

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

Użycie:

const handleInput = () => console.log('Search triggered');
document.getElementById('search').addEventListener('input', debounce(handleInput, 500));

Gotowe rozwiązania

Jeśli nie chcesz pisać własnych implementacji, możesz skorzystać z biblioteki Lodash, która oferuje _.throttle i _.debounce:

import { throttle, debounce } from 'lodash';

const throttled = throttle(() => console.log('Throttle!'), 200);
const debounced = debounce(() => console.log('Debounce!'), 300);

Praktyczne przykłady

Przykład 1: Throttling – ładowanie nowych elementów przy przewijaniu

Scenariusz:

Masz listę produktów, która ładuje więcej elementów, gdy użytkownik zbliża się do końca strony. Nie chcesz, żeby funkcja ładowania była wywoływana dziesiątki razy w ciągu sekundy przy szybkim przewijaniu.

Kod:

<!DOCTYPE html>
<html>
<body style="height: 2000px">
  <script>
    function throttle(func, limit) {
      let lastRun = 0;
      return function(...args) {
        const now = Date.now();
        if (now - lastRun >= limit) {
          lastRun = now;
          func.apply(this, args);
        }
      };
    }

    function loadMoreItems() {
      console.log('Ładowanie nowych elementów...');
    }

    window.addEventListener('scroll', throttle(() => {
      if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) {
        loadMoreItems();
      }
    }, 300));
  </script>
</body>
</html>

Przykład 2: Debouncing – wyszukiwanie przy wpisywaniu

Scenariusz:

Masz pole wyszukiwania. Nie chcesz wysyłać zapytania do serwera z każdą literą, ale dopiero, gdy użytkownik przestanie pisać na chwilę.

Kod:

<!DOCTYPE html>
<html>
<body>
  <input type="text" id="search" placeholder="Wpisz zapytanie..." />

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

    function fetchResults(query) {
      console.log(`Szukam wyników dla: "${query}"`);
    }

    const searchInput = document.getElementById('search');
    searchInput.addEventListener('input', debounce(function(e) {
      fetchResults(e.target.value);
    }, 500));
  </script>
</body>
</html>

Przykład 3: Debouncing – autozapis treści po edycji

Scenariusz:

Użytkownik pisze notatkę. Chcesz zapisać treść automatycznie, ale nie po każdej literze – dopiero, gdy przestanie pisać na np. 1 sekundę.

Kod:

<!DOCTYPE html>
<html>
<body>
  <textarea id="note" placeholder="Pisz notatkę..." rows="10" cols="40"></textarea>

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

    function autosave(content) {
      console.log(`Autozapis: ${content}`);
    }

    const noteArea = document.getElementById('note');
    noteArea.addEventListener('input', debounce(function(e) {
      autosave(e.target.value);
    }, 1000));
  </script>
</body>
</html>

Przykład 4: Throttling – śledzenie pozycji myszy

Scenariusz:

Potrzebujesz aktualizować współrzędne myszy, np. do tooltipa lub gry, ale tylko kilka razy na sekundę, by nie przeciążyć renderowania.

Kod:

<!DOCTYPE html>
<html>
<body>
  <div id="output">Pozycja: X=0, Y=0</div>

  <script>
    function throttle(func, limit) {
      let lastRun = 0;
      return function(...args) {
        const now = Date.now();
        if (now - lastRun >= limit) {
          lastRun = now;
          func.apply(this, args);
        }
      };
    }

    function updateMousePosition(e) {
      document.getElementById('output').textContent = `Pozycja: X=${e.clientX}, Y=${e.clientY}`;
    }

    document.addEventListener('mousemove', throttle(updateMousePosition, 100));
  </script>
</body>
</html>

Podsumowanie przykładów

Sytuacja życiowa Technika Korzyść
Scrollowanie listy z lazy-loadingiem Throttle Rzadziej ładowanie danych, mniejsze zużycie
Pole wyszukiwania z autouzupełnianiem Debounce Mniej zapytań, szybsza odpowiedź serwera
Autozapis podczas pisania Debounce Zapis tylko po zakończeniu pisania
Śledzenie kursora myszy w interfejsie Throttle Płynniejsze animacje, lepsza wydajność

Kiedy używać której techniki?

Sytuacja Użyj
Scrollowanie strony i ładowanie danych Throttle
Wyszukiwanie po wpisaniu tekstu Debounce
Automatyczne zapisywanie danych Debounce (po edycji) lub Throttle (cyklicznie)
Reagowanie na resize okna Throttle
Walidacja formularza przy wpisywaniu Debounce

Podsumowanie

Throttling i debouncing to dwie kluczowe techniki optymalizacji wydajności JavaScript w aplikacjach webowych. Znając ich różnice i zastosowania, możemy tworzyć bardziej responsywne, płynne i przyjazne użytkownikowi interfejsy. Obie techniki są łatwe do wdrożenia, a stosowanie ich w odpowiednich miejscach to znak dojrzałego i świadomego programowania frontendowego.

6 czerwca 2025 20

Kategorie

programowanie

Tagi

javascript

Dziękujemy!
()

Powiązane wpisy


Informacja o cookies

Moja strona internetowa wykorzystuje wyłącznie niezbędne pliki cookies, które są wymagane do jej prawidłowego działania. Nie używam ciasteczek w celach marketingowych ani analitycznych. Korzystając z mojej strony, wyrażasz zgodę na stosowanie tych plików. Możesz dowiedzieć się więcej w mojej polityce prywatności.