Debouncing and Throttling in JavaScript
Description
Debouncing and throttling are two techniques used to control the execution frequency of functions, commonly employed to optimize frequently triggered events (such as scrolling, input, window resizing, etc.). The core of debouncing is "delayed execution"—when an event is triggered frequently, the function executes only after a period of inactivity following the last trigger. The core of throttling is "diluted execution"—it ensures that the function is executed at most once within a specified time interval.
Problem-Solving Process
-
Understanding the Scenario
Imagine a search box where user input triggers real-time requests to a server. Without control, sending a request for every character typed would cause significant performance waste. We need to limit the request frequency. -
Implementation Idea for Debouncing
-
Core Concept: After an event is triggered, wait for a set delay time (e.g., 500 ms). If the event is triggered again within this delay, cancel the previous wait and restart the timer. The function executes only after a trigger is followed by the full delay period without another trigger.
-
Real-Life Analogy: Like an elevator's automatic door closing. When the door opens, if people keep entering (frequent triggers), the elevator continually resets the closing timer. Only after the last person enters and no one else enters for a while does the door close (function execution).
-
Implementation Steps:
a. Create a higher-order function that accepts two parameters: the original functionfuncto be debounced and the delay timewait.
b. Inside the higher-order function, define a variable (e.g.,timeoutId) to store the timer identifier.
c. Return a new function (e.g., a closure).
d. Inside this new function, on each call, first clear any existing timer usingclearTimeout(timeoutId).
e. Then set a new timer to execute the originalfuncafterwaitmilliseconds.
f. Assign the identifier of the new timer totimeoutId. -
Basic Code Implementation:
function debounce(func, wait) { let timeoutId; // Stores the timer ID // Returns the debounced function return function (...args) { // Clear the previous timer clearTimeout(timeoutId); // Set a new timer timeoutId = setTimeout(() => { func.apply(this, args); // Use apply to ensure correct `this` context and arguments for func }, wait); }; } -
Usage Example:
// A mock search function function search(query) { console.log(`Searching for: ${query}`); } // Debounce the search function with a 500 ms delay const debouncedSearch = debounce(search, 500); // Simulate rapid input debouncedSearch('a'); // Canceled debouncedSearch('ap'); // Canceled debouncedSearch('app'); // Canceled // After 500 ms, only one log appears: Searching for: app
-
-
Implementation Idea for Throttling
-
Core Concept: Ensures a function is executed at most once within a fixed time interval. Regardless of how frequently the event fires, the function executes regularly at the set interval.
-
Real-Life Analogy: Like a water tap—even if you turn the valve fully open (frequent triggers), water flows at a constant rate (function executes regularly).
-
Implementation Steps (using timestamps):
a. Create a higher-order function acceptingfuncand intervalwait.
b. Define two variables:lastExecTime(timestamp of last execution) andtimeoutId(timer ID, for trailing call).
c. Return a new function.
d. Inside this new function, get the current timecurrentTime.
e. Calculate the time remaining until the next allowed execution:remaining = wait - (currentTime - lastExecTime).
f. Ifremaining <= 0, the interval has passed, so execute the function immediately, updatinglastExecTimetocurrentTime.
g. If no timer is pending andremaining > 0, set a timer to execute the function afterremainingmilliseconds (ensuring the last trigger is also handled). -
Code Implementation:
function throttle(func, wait) { let lastExecTime = 0; // Last execution timestamp let timeoutId; // Timer ID return function (...args) { const currentTime = Date.now(); const remaining = wait - (currentTime - lastExecTime); // If the interval has passed, or system time was adjusted (currentTime < lastExecTime) if (remaining <= 0 || currentTime < lastExecTime) { // Clear any pending trailing call timer clearTimeout(timeoutId); timeoutId = null; lastExecTime = currentTime; func.apply(this, args); } // If within the interval and no trailing call timer is set else if (!timeoutId) { timeoutId = setTimeout(() => { lastExecTime = Date.now(); // Update last execution time with current time timeoutId = null; func.apply(this, args); }, remaining); } }; } -
Usage Example:
// A function to handle scroll events function handleScroll() { console.log(`Window scrolled, current position: ${window.scrollY}`); } // Throttle handleScroll to execute at most once every 200 ms const throttledScrollHandler = throttle(handleScroll, 200); // When the user scrolls quickly, handleScroll will be called at most every 200 ms, not on every scroll event. window.addEventListener('scroll', throttledScrollHandler);
-
-
Comparison and Choice Between Debouncing and Throttling
- Debouncing: Suitable for scenarios where you need the action only once after a continuous event ends.
- Examples: Search box input suggestions, window
resizeevent (wait until the user finishes resizing before recalculating layout).
- Examples: Search box input suggestions, window
- Throttling: Suitable for continuous events where you need to maintain a certain execution frequency.
- Examples: Infinite scroll on page scroll (
scroll), mouse movement (mousemove), rate-limiting in shooting games.
- Examples: Infinite scroll on page scroll (
- Debouncing: Suitable for scenarios where you need the action only once after a continuous event ends.
Summary
Debouncing and throttling are highly practical techniques in front-end performance optimization. Debouncing ensures final single execution via "resetting delay," ideal for handling "outcomes." Throttling ensures execution frequency via a "fixed interval," ideal for handling "processes." Understanding their core concepts and mastering their implementation is crucial for managing high-frequency events.