Skip to main content

Що таке "debounce" і "throttle" при запитах?

Проблема, яку вони вирішують

Якщо користувач швидко друкує в полі пошуку:

javascript
R Re Rea Reac React

і при кожному натисканні ти відправляєш запит:

javascript
fetch(`/api/search?q=${query}`);

то сервер отримає 5-10 запитів за секунду, хоча потрібен лише останній. Це:

  • навантажує сервер,
  • створює зайві setState і перемальовування,
  • може призвести до "гонки" даних (стара відповідь приходить пізніше нової).

Тут і допомагають debounce і throttle - способи контролювати частоту викликів функцій (наприклад, мережевих запитів).


1. Debounce (усунення тремтіння)

Debounce - відкладає виконання функції, поки користувач не перестане викликати її протягом заданого часу.

Тобто:

  • кожен новий виклик скидає таймер;
  • функція спрацює лише після паузи.

Приклад

javascript
function debounce(fn, delay) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); }; }

Використання в React:

javascript
const debouncedSearch = useMemo( () => debounce((value) => fetch(`/api/search?q=${value}`), 500), [] ); <input onChange={(e) => debouncedSearch(e.target.value)} />;

Користувач друкує:

javascript
r → re → rea → reac → react

-> fetch() виконається один раз, через 500 мс після останнього вводу.

Чудово підходить для:

  • пошукових запитів;
  • автокомпліту;
  • фільтрації при вводі;
  • перевірки унікальності імені/email при вводі.

2. Throttle (обмеження частоти)

Throttle - дозволяє виконувати функцію не частіше, ніж раз на заданий інтервал.

Тобто:

  • перший виклик відбувається одразу;
  • наступні ігноруються, поки не мине таймер.

Приклад

javascript
function throttle(fn, delay) { let last = 0; return (...args) => { const now = Date.now(); if (now - last >= delay) { last = now; fn(...args); } }; }

Використання в React:

javascript
const throttledScroll = useMemo( () => throttle((event) => console.log(window.scrollY), 200), [] ); useEffect(() => { window.addEventListener('scroll', throttledScroll); return () => window.removeEventListener('scroll', throttledScroll); }, [throttledScroll]);

При прокручуванні 60 разів/секунда -> обробник викличеться лише кожні 200 мс (≈5 разів/секунда).

Чудово підходить для:

  • обробників scroll, resize, mousemove;
  • оновлення позиції, видимості елементів;
  • "infinite scroll".

Порівняння

ОсобливістьDebounceThrottle
Коли виконуєтьсяпісля паузичерез рівні інтервали
Поведінка при частих викликахчекає на "тишу"запускається періодично
Підходить дляпошуку, вводу текстускролу, ресайзу, drag-and-drop
Кількість викликівмінімумобмежена
UX ефект"чекає, поки користувач закінчить""обмежує частоту оновлень"

Комбінований приклад (пошук з debounce)

javascript
import { useState, useMemo, useEffect } from "react"; function debounce(fn, delay) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), delay); }; } export function SearchBox() { const [query, setQuery] = useState(""); const [results, setResults] = useState([]); const search = useMemo( () => debounce(async (q) => { const res = await fetch(`/api/search?q=${q}`); setResults(await res.json()); }, 400), [] ); useEffect(() => { if (query) search(query); }, [query, search]); return ( <div> <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Пошук..." /> <ul>{results.map(r => <li key={r.id}>{r.name}</li>)}</ul> </div> ); }

Користувач друкує - запит виконується лише після 400 мс "тиші".


Підсумок

Що робитьЯк працюєДе використовувати
Debounceчекає, поки користувач перестане викликати функціюпошук, фільтр, валідація при вводі
Throttleвиконує не частіше, ніж кожні X мсscroll, resize, drag, infinite-scroll
Обидвазахищають від "шторму викликів" і знижують навантаженняпідвищують UX і продуктивність

Коротко:

Debounce - "виконай, коли користувач закінчить". Throttle - "виконуй не частіше, ніж раз на N мс".

Обидва потрібні, щоб не спамити сервер і не блокувати UI зайвими рендерами при частих подіях.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.