Debounce with Immediate Flag (Leading Edge Execution)
What is Debounce?
Debouncing is a technique used to limit how often a function executes when it is triggered repeatedly within a short period of time.
Instead of running a function on every event, debounce delays execution until the user stops triggering the event for a specified amount of time.
Without Debounce
If a user types 10 characters:
h
he
hel
hell
hello
...An API request may fire 10 times.
With Debounce
The API request only fires once, after the user stops typing for the specified delay.
User typing → Typing → Typing → Stop
↓
API Call1. Why Do We Need Debounce?
Debounce helps:
- Reduce unnecessary API calls
- Improve performance
- Prevent excessive re-renders
- Avoid expensive calculations
- Improve user experience
2. Real Frontend Use Cases
1. Search Autocomplete
Without debounce:
<input onChange={handleSearch} />Every keystroke sends a request.
r → API
re → API
rea → API
reac → API
react → APIWith debounce:
User types "react"
↓
Wait 500ms
↓
Single API Call2. Window Resize
window.addEventListener("resize", handleResize);Dragging the browser window may trigger hundreds of events.
Debounce prevents excessive calculations.
3. Form Validation
<input onChange={validateEmail} />Instead of validating on every keystroke:
a
ab
abc
abc@
abc@gValidate only when user pauses typing.
4. Saving Drafts
Google Docs style auto-save:
saveDraft();Debounce ensures saves happen after the user pauses typing.
3. Basic Debounce Implementation
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}Example
const search = debounce((value) => {
console.log("Searching:", value);
}, 500);
search("r");
search("re");
search("rea");
search("react");Output:
Searching: reactOnly the last call executes.
4. Understanding the Immediate (Leading Edge) Flag
Normally debounce executes on the trailing edge.
User clicks
User clicks
User clicks
Wait 500ms
↓
Function ExecutesSometimes we want the function to run immediately on the first call, then ignore subsequent calls until the delay expires.
This is called leading edge execution.
The immediate flag enables this behavior.
5. Debounce with Immediate Flag Implementation
function debounce(fn, delay, immediate = false) {
let timer;
return function (...args) {
const callNow = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
if (!immediate) {
fn.apply(this, args);
}
}, delay);
if (callNow) {
fn.apply(this, args);
}
};
}How It Works
Immediate = false (Default)
const log = debounce(() => console.log("Executed"), 1000, false);Timeline:
Click
Click
Click
Wait 1s
↓
ExecutedOnly after the user stops triggering events.
Immediate = true
const log = debounce(() => console.log("Executed"), 1000, true);Timeline:
Click
↓
Executed Immediately
Click
Click
Click
↓
Ignored
After 1 second
Click
↓
Executed AgainVisual Comparison
Trailing Debounce
Event Event Event Event
↓
Wait
↓
ExecuteLeading Debounce (Immediate)
Event
↓
Execute
Event Event Event
↓
Ignored
Delay Ends
Event
↓
ExecuteJavaScript Example
Prevent Multiple Button Clicks
const submitOrder = debounce(
() => {
console.log("Order Submitted");
},
3000,
true,
);
button.addEventListener("click", submitOrder);Why?
Prevents users from:
Click
Click
Click
ClickSubmitting multiple orders accidentally.
React Example
Search Input
import { useMemo } from "react";
function Search() {
const debouncedSearch = useMemo(
() =>
debounce((value) => {
console.log("Searching:", value);
}, 500),
[],
);
return (
<input
onChange={(e) => debouncedSearch(e.target.value)}
placeholder="Search..."
/>
);
}React Example with Immediate Flag
Prevent Multiple Form Submissions
import { useMemo } from "react";
function SignupForm() {
const handleSubmit = useMemo(
() =>
debounce(
() => {
console.log("Form Submitted");
},
3000,
true,
),
[],
);
return <button onClick={handleSubmit}>Submit</button>;
}Behavior:
First Click
↓
Form Submitted
Next Clicks (within 3 seconds)
↓
Ignored6. Common Interview Q&A
Difference Between Debounce and Throttle?
Debounce
Executes after events stop.
Typing...
Typing...
Typing...
Stop
↓
ExecuteThrottle
Executes at most once every specified interval.
Scroll
↓
Execute
Scroll
↓
Ignored
1 second later
Scroll
↓
ExecuteCommon Interview Questions
Q1. Why use fn.apply(this, args)?
It:
- Preserves the original
this - Passes all arguments correctly
fn.apply(this, args);Equivalent to:
fn.call(this, ...args);Q2. Why clear the timeout?
clearTimeout(timer);It cancels the previous scheduled execution.
Without it, every event would create a new timer.
Q3. Why set timer = null?
timer = null;Allows future leading-edge executions when:
Delay Ends
↓
Next Event
↓
Execute Again7. Production Use Cases for Immediate Debounce
Most common uses:
Search Inputs
debounce(searchUsers, 500);Auto Save
debounce(saveDraft, 1000);Window Resize
debounce(handleResize, 250);Prevent Double Submission
debounce(submitForm, 3000, true);Prevent Multiple Payment Requests
debounce(processPayment, 5000, true);8. Complexity Analysis
Time Complexity
O(1)Each call only:
- Clears a timer
- Creates a timer
Space Complexity
O(1)Only one timeout reference is stored.
Key Takeaways
- Debouncing: Delaying a function execution until a specific amount of time has elapsed since the last call.
- Immediate Flag: Executes the callback immediately on the leading edge of the input series rather than waiting for the trailing edge.
- Keystroke Events: Ideal for search autocompletes, window resizes, and double-submit prevention.
- Complexity: $O(1)$ space and time operations for scheduling browser timers asynchronously.