Skip to main content

What are "debounce" and "throttle" for requests?

The problem they solve

If a user types quickly in a search field:

javascript
R Re Rea Reac React

and on every keystroke you send a request:

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

then the server gets 5-10 requests per second, even though only the last one is needed. This:

  • overloads the server,
  • creates unnecessary setState calls and re-renders,
  • can cause a data "race" (an old response arriving after a newer one).

This is where debounce and throttle help - ways to control how often functions are called (for example, network requests).


1. Debounce

Debounce delays running a function until the user stops calling it for a given amount of time.

That is:

  • every new call resets the timer;
  • the function fires only after a pause.

Example

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

Usage in React:

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

The user types:

javascript
r → re → rea → reac → react

-> fetch() runs once, 500 ms after the last keystroke.

Great for:

  • search requests;
  • autocomplete;
  • filtering as you type;
  • checking whether a name/email is unique while typing.

2. Throttle

Throttle lets a function run no more often than once per given interval.

That is:

  • the first call happens immediately;
  • subsequent calls are ignored until the timer expires.

Example

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

Usage in React:

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

When scrolling fires 60 times a second -> the handler runs only every 200 ms (about 5 times a second).

Great for:

  • scroll, resize, mousemove handlers;
  • updating position, element visibility;
  • "infinite scroll".

Comparison

TraitDebounceThrottle
When it runsafter a pauseat regular intervals
Behavior on frequent callswaits for "silence"fires periodically
Good forsearch, text inputscroll, resize, drag-and-drop
Number of callsminimalcapped
UX effect"waits until the user finishes""limits how often updates happen"

A combined example (search with 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="Search..." /> <ul>{results.map(r => <li key={r.id}>{r.name}</li>)}</ul> </div> ); }

The user types - the request runs only after 400 ms of "silence".


Summary

What it doesHow it worksWhere to use it
Debouncewaits until the user stops calling the functionsearch, filters, validation while typing
Throttleruns no more often than every X msscroll, resize, drag, infinite-scroll
Bothprotect against a "storm of calls" and reduce loadimprove UX and performance

In short:

Debounce - "run it once the user is done". Throttle - "run it no more than once every N ms".

Both are needed to avoid spamming the server and blocking the UI with unnecessary renders during frequent events.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.