What is Throttling in JavaScript? Throttling implies limiting the number of times a function gets called in a certain time period. It will prohibit a function from executing if we have invoked it “recently.” Throttling also guarantees that a function runs at a consistent rate. Throttling or sometimes also called throttle function, is a practice used in websites.
To better understand throttling, consider the following example. Assume you’re heading to an ATM to get some cash. The bank’s guidelines state that you may only withdraw cash once every hour. You proceeded to withdraw cash from the ATM. You afterward discovered that you require additional funds. When you attempted to withdraw more cash, the ATM rejected your request, stating that you could only do so after an hour. No matter how many times you attempt, the ATM will deny your request until one hour has passed since your last transaction. It is known as throttling. We are rate-limiting a function execution over a period of time, in this case, one hour, for performing an ATM transaction.
When to Use Throttling? Throttling is suitable for scenarios where you want to limit how often a function can be called, but you don’t want to miss any calls. For example, you might want to use throttling for:
- Fetching data from an API or a database when the user scrolls, resizes, or types
- Updating or animating elements on the page when the user scrolls, resizes, or moves the mouse
- Logging or tracking user actions or events when they occur frequently
Here are three simple real life examples of throttling:
- Scrolling Event: Update UI every 100ms.
- API Rate Limiting: Send requests once per second.
- Window Resize: Adjust layout every 200ms.
- Button Clicks: Limit clicks to prevent multiple submissions.
- Mouse Move Events: Update element position every 50ms.
- Infinite Scrolling: Load content periodically.
- Game Loops: Control frame rate for smooth performance.
- Search Input Autocomplete: Query server every 300ms.
What is Difference between throttle and debounce ?
- Throttle: Executes the function at regular intervals, controlling the rate at which it runs over time.
- Debounce: Executes the function only after a specified period of inactivity, ensuring it runs only once after the last call.
https://bigfrontend.dev/problem/implement-basic-throttle
Throttling is a common technique used in Web Application, in most cases using lodash solution would be a good choice.
could you implement your own version of basic throttle()
?
In case you forgot, throttle(func, delay)
will return a throttled function, which will invoke the func at a max frequency no matter how throttled one is called.
Here is an example.
Before throttling we have a series of calling like
─A─B─C─ ─D─ ─ ─ ─ ─ ─ E─ ─F─G
After throttling at wait time of 3 dashes
─A─ ─ ─C─ ─ ─D ─ ─ ─ ─ E─ ─ ─G
Be aware that
- call A is triggered right way because not in waiting time
- function call B is swallowed because B, C is in the cooling time from A, and C is latter.
notes
-
please follow above spec. the behavior is not exactly the same as
lodash.throttle()
-
because
window.setTimeout
andwindow.clearTimeout
are not accurate in browser environment, they are replaced to other implementation when judging your code. They still have the same interface, and internally keep track of the timing for testing purpose.
Something like below will be used to do the test.
let currentTime = 0;
const run = (input) => {
currentTime = 0;
const calls = [];
const func = (arg) => {
calls.push(`${arg}@${currentTime}`);
};
const throttled = throttle(func, 3);
input.forEach((call) => {
const [arg, time] = call.split('@');
setTimeout(() => throttled(arg), time);
});
return calls;
};
expect(run(['A@0', 'B@2', 'C@3'])).toEqual(['A@0', 'C@3']);
/**
* @param {Function} func
* @param {number} wait
*/
function throttle(func, wait) {
// Track if we are waiting. Initially, we are not.
let isWaiting = false;
// Track arguments of last call
let lastCallArgs = null;
return function throttled(...args) {
// If we are waiting,
if (isWaiting) {
// ...store arguments of last call
lastCallArgs = args;
return;
}
// If we are not waiting, execute 'func' with passed arguments
func.apply(this, args);
// Prevent future execution of 'func'
isWaiting = true;
// After wait time,
setTimeout(() => {
// ...allow execution of 'func'
isWaiting = false;
// If arguments of last call exists,
if (lastCallArgs) {
// ...execute function throttled and pass last call's arguments
// to it. Since now we are not waiting, 'func' will be executed
// and isWaiting will be reset to true.
throttled.apply(this, lastCallArgs);
// ...reset arguments of last call to null.
lastCallArgs = null;
}
}, wait);
};
}
function logHi() {
console.log("Hi");
}
const throttledLogHi = throttle(logHi, 500);
throttledLogHi(); // Hi
throttledLogHi(); // (nothing)
throttledLogHi(); // (nothing)
throttledLogHi(); // (nothing)
The throttle
function is designed to limit the number of times a function can be executed over a certain period. In this case, the wait
time is set to 500 milliseconds.
Here's a step-by-step explanation of what happens when you call throttledLogHi
four times in quick succession:
-
Call
throttledLogHi
the first time:isWaiting
isfalse
, sologHi
is executed immediately and "Hi" is logged to the console. ThenisWaiting
is set totrue
, which preventslogHi
from being executed again untilisWaiting
is set back tofalse
after thewait
time has passed. -
Call
throttledLogHi
the second, third, and fourth time: These calls happen whileisWaiting
is stilltrue
, sologHi
is not executed and nothing is logged to the console. ThelastCallArgs
are updated with the arguments of the last call, but sincelogHi
doesn't take any arguments, this doesn't have any effect. -
After the
wait
time has passed,isWaiting
is set back tofalse
. If there were any calls tothrottledLogHi()
during thewait
time (which there were),logHi
is executed again with the arguments of the last call (which werenull
), and "Hi" is logged to the console again.
This is why you see "Hi" logged to the console twice, even though throttledLogHi()
was called four times. The throttling mechanism ensures that logHi
is not called more than once every 500 milliseconds, regardless of how many times throttledLogHi
is called.