Debounce, Throttle, Cancel – Optimizing API Calls Like a Pro


We’ve all done it.
Tied an onChange
to an API call. Typed a letter.
And boom — 10 requests in under 3 seconds.
Your server? Crying.
Your app? Lagging.
Your recruiter watching your portfolio? Closing the tab.
Today we fix that.
We’re diving into:
Why API overcalling happens
What debounce, throttle, and cancel actually do
Real React patterns to apply them
And some gotchas no one warns you about
The Problem: Too Many API Calls
Common Culprits:
Search inputs (
onChange
→fetch
)Scroll or resize listeners
Auto-save features
Live filtering / autocomplete
Without guards, these become network abuse.
Worse: results arrive out of order and your UI starts flickering like a strobe light.
Debounce vs Throttle vs Cancel – The Trio Explained
Method | What It Does | Best For |
Debounce | Waits for a pause before calling | Search bars, typing |
Throttle | Ensures calls happen at a fixed rate | Scroll, resize |
Cancel | Aborts in-progress calls | Rapid input, route changes |
Debounce – Let Them Finish Typing, Please
📦 Pattern:
Only make the API call after the user stops typing for a bit.
import { useEffect, useState } from 'react';
function useDebouncedValue(value: string, delay: number) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
Now use it like:
const [query, setQuery] = useState('');
const debouncedQuery = useDebouncedValue(query, 500);
useEffect(() => {
if (debouncedQuery) fetchData(debouncedQuery);
}, [debouncedQuery]);
You reduced API load without sacrificing UX.
Throttle – One Call Per Interval, No Matter What
function throttle(func, limit) {
let inThrottle = false;
return function (...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
}
Useful for:
Tracking scroll position
Resizing windows
Events that fire constantly but don’t need real-time reaction
Cancel – Prevent Overlapping or Stale Requests
Using AbortController
:
useEffect(() => {
const controller = new AbortController();
fetch(`/api/search?q=${query}`, { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') console.error(err);
});
return () => controller.abort();
}, [query]);
When to Cancel:
User changes input before response comes back
Route/page changes mid-request
Revalidating stale data
This is how you avoid "response from previous query overwriting new data."
Common Pitfalls
Problem | Fix |
Request from old input overwrites new results | Use AbortController |
Debounce too short = still spam | 300–600ms is the sweet spot |
Forgetting cleanup in useEffect | Always return a cleanup function |
Overusing throttle on sensitive UI | Throttle carefully — it feels laggy if abused |
Bonus: Use Libraries to Save Time
Lodash –
debounce
&throttle
baked inReact Query – Handles canceling, caching, retries
SWR – Handles deduping and revalidation
[axios.CancelToken (deprecated) → use
AbortController
instead now
Final Thoughts
Your API calls shouldn’t:
Choke your server
Race each other like Tokyo Drift
Make your UI look like a glitchy game
With debounce, throttle, and cancel, you:
Keep things smooth
Stay performant
And look like a dev who respects rate limits
📚 This is Awaiting Response(),
Where we don’t just fetch — we fetch with grace, speed, and dignity.
Next up:
Caching Like You Mean It – SWR, React Query & Beyond
Because sometimes, the best API call… is the one you don’t make 😎
Subscribe to my newsletter
Read articles from Faiaz Khan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Faiaz Khan
Faiaz Khan
Hey! I'm Faiaz — a frontend developer who loves writing clean, efficient, and readable code (and sometimes slightly chaotic code, but only when debugging). This blog is my little corner of the internet where I share what I learn about React, JavaScript, modern web tools, and building better user experiences. When I'm not coding, I'm probably refactoring my to-do list or explaining closures to my cat. Thanks for stopping by — hope you find something useful or mildly entertaining here.