admin管理员组文章数量:1125802
Can anyone give me an in-simple-words explanation about the difference between throttling and debouncing a function for rate-limiting purposes?
To me, both seem to do the same the thing. I have checked these two blogs to find out, but I'm still having trouble understanding.
/
Can anyone give me an in-simple-words explanation about the difference between throttling and debouncing a function for rate-limiting purposes?
To me, both seem to do the same the thing. I have checked these two blogs to find out, but I'm still having trouble understanding.
http://remysharp.com/2010/07/21/throttling-function-calls
http://benalman.com/projects/jquery-throttle-debounce-plugin/
Share Improve this question edited Nov 16, 2023 at 16:37 zcoop98 3,0712 gold badges22 silver badges37 bronze badges asked Sep 23, 2014 at 9:19 bhavya_wbhavya_w 10k9 gold badges31 silver badges41 bronze badges 6- 337 This is a good visualization – thriqon Commented Sep 23, 2014 at 9:31
- Very simple example that helped me to understand. jsfiddle.net/Voronar/sxjy25ew/1 – Kirill A. Khalitov Commented May 22, 2017 at 9:36
- 9 Can see the visualization here as well codepen.io/chriscoyier/pen/vOZNQV – trungvose Commented Jul 4, 2017 at 10:23
- For simple and plain JS implementations of throttle and bounce, see my answer on Simple throttle in js. – akinuri Commented Jul 24, 2018 at 7:43
- 5 I'm not a fan of linking to personal websites, as history has shown that most of them will go offline some day. Therefore, I have recorded the debounce demo from nimus so that if it's gone in the future, people still can see it here: imgur.com/PkwDnfy – Advena Commented Oct 1, 2021 at 8:18
28 Answers
Reset to default 704To put it in simple terms:
- Throttling will delay executing a function. It will reduce the notifications of an event that fires multiple times.
- Debouncing will bunch a series of sequential calls to a function into a single call to that function. It ensures that one notification is made for an event that fires multiple times.
You can visually see the difference in this demo, which shows when a debounced vs throttled event would fire based on mouse movement.
If you have a function that gets called a lot - for example when a resize or mouse move event occurs, it can be called a lot of times. If you don't want this behaviour, you can Throttle it so that the function is called at regular intervals. Debouncing will mean it is called at the end (or start) of a bunch of events.
Differences
Debounce 1 second | Throttle 1 second | |
---|---|---|
Outputs if… | 1 second has elapsed since the last input | 1 second has elapsed since the last output |
Delay between… | input and output | output and output |
Explanation by use case
- Search bar: Don't want to search for a term every time the user presses a key? Want instead to search after the user stopped typing for 1 second? Use
debounce
1 second on key press. - Shooting game: Don't want to fire a pistol every time the user clicks the mouse? Want instead to fire at most every 1 second? Use
throttle
1 second on mouse click.
Reversing their roles
- Throttling the search for 1 second: If a user types "abcde", with each subsequent character getting typed every 0.6 seconds, then
throttle
will trigger a search at the "a" press. It will then ignore every press for the next 1 second, so "b" at 0.6 second will be ignored. Then it will again trigger a search at the "c" press at 1.2 seconds will again trigger a search, which resets the time. "d" at 1.8 seconds will be ignored. Finally it will again trigger a search at the "e" press at 2.4 seconds. - Debouncing the pistol for 1 second: When a user sees an enemy, he clicks the mouse, but
debounce
will not fire the pistol. He will click again several times in that second but it will still be ignored. Only after ceasing his clicks for a full second will the pistol finally fire, one single shot.
A "real life" comparison
There are some guards outside a bar. Guards allow a person who says "I want to go in" inside the bar. This is a normal scenario. Anyone saying "I want to go in" is allowed to go inside the bar.
Now there is a Throttle Guard (throttle 5 seconds). He likes people who respond first. Anyone who says "I will go" first, he allows that person inside. Then he rejects every person for the next 5 seconds. After that, again anyone saying it first will be allowed and others will be rejected for the next 5 seconds.
There is another guard, the Debounce Guard (debounce 5 seconds). He likes people who bring mental rest to him for 5 seconds. So if any person says "I will go", the guard waits for 5 seconds. If no other person disturbs him in those 5 seconds, he allows the first person inside. But, if some other person interrupts and says "I will go" in those 5 seconds, he will reject the first one, and again start the 5 seconds of waiting, this time for the second person. If 5 seconds pass without interruption now, that second person will be let in, but not the first.
Personally I found debounce harder to comprehend than throttle.
As both functions help you postpone and reduce the rate of some execution. Assuming you are calling decorated functions returned by throttle/debounce repeatedly...
- Throttle: the original function will be called at most once per specified period.
- Debounce: the original function will be called after the caller stops calling the decorated function after a specified period.
I found the last part of debounce crucial to understand the goal it's trying to achieve. I also found an old version of the implementation of _.debounce helps the understanding (courtesy of https://davidwalsh.name/function-debounce).
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
A far-fetched metaphor, but maybe could also help.
You have a friend named Chatty who likes to talk with you via IM. Assuming when she talks she sends a new message every 5 seconds, while your IM application icon is bouncing up and down, you can take the...
- Naive approach: check every message as long as it arrives. When your app icon bounces, check. It's not the most effective way, but you are always up-to-date.
- Throttle approach: you check once every 5 minutes (when there are new ones). When new message arrives, if you have checked anytime in the last 5 minutes, ignore it. You save your time with this approach, while still in the loop.
- Debounce approach: you know Chatty, she breaks down a whole story into pieces, sends them in one message after another. You wait until Chatty finishes the whole story: if she stops sending messages for 5 minutes, you would assume she has finished, now you check all.
Throttle (1 sec): Hello, I am a robot. As long as you keep pinging me, I will keep talking to you, but after exactly 1 second each. If you ping me for a reply before a second is elapsed, I will still reply to you at exactly 1 second interval. In other words, I just love to reply at exact intervals.
Debounce (1 sec): Hi, I am that ^^ robot's cousin. As long as you keep pinging me, I am going to remain silent because I like to reply only after 1 second is passed since the last time you pinged me. I don't know, if it is because I have an attitude problem or because I just don't like to interrupt people. In other words, if you keep asking me for replies before 1 second is elapsed since your last invocation, you will never get a reply. Yeah yeah...go ahead! call me rude.
Throttle (10 min): I am a logging machine. I send system logs to our backend server, after a regular interval of 10 minutes.
Debounce (10 sec): Hi, I am not cousin of that logging machine. (Not every debouncer is related to a throttler in this imaginary world). I work as a waiter in a nearby restaurant. I should let you know that as long as you keep adding stuff to your order, I will not go to the kitchen for execution of your order. Only when 10 seconds have elapsed after you last modified your order, I will assume that you are done with your order. Only then will I go and execute your order in the kitchen.
Cool Demos: https://css-tricks.com/debouncing-throttling-explained-examples/
Credits for the waiter analogy: https://codeburst.io/throttling-and-debouncing-in-javascript-b01cad5c8edf
- Throttling enforces a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds."
- Debouncing enforces that a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called."
Source
It's simpler than the demos.
When throttle is being called it fires your function periodically (eg. every 20ms) – and once at the end.
Debounce only fires at the end (eg. 20ms after the last event).
So, as long as events continue to fire rapidly (eg. in intervals of less than 20ms), debounce will remain silent, while throttle will fire once every 20ms. Both will fire at the end, the difference is only throttle will also fire in-between at set intervals.
Example: If you're scrolling, throttle will slowly call your function while you scroll (every X milliseconds). Debounce will wait until after you're done scrolling to call your function (possibly only once).
I like to think of throttle as "including debounce", they both make a final call after the events are done, but due to implementation details, the two don't always make this final call at the exact same time, making demos confusing.
In layman's terms:
Debouncing will prevent a function from running while it is still being called frequently. A debounced function will only run after it has been determined that it is no longer being called, at which point it will run exactly once. Practical examples of debouncing:
Auto-saving or validating the contents of a text-field if the user "stopped typing": the operation will only be done once, AFTER it has been determined that the user is no longer typing (no longer pressing keys).
Logging where users rest their mouse: the user is no longer moving their mouse, so the (last) position can be logged.
Throttling will simply prevent a function from running if it has run recently, regardless of the call frequency. Practical examples of throttling:
- Implementations of v-sync are based on throttling: the screen will only be drawn if 16ms elapsed since the last screen draw. No matter how many times the screen refresh functionality is called, it will only run at most once every 16ms.
A picture is worth a thousand words
Throttle
Debounce
Notice the Debounce will not fire until the events flow stops. However, Throttle will fire an event each interval.
(Thanks to css-tricks)
A real-life analogy that personally helps me remember:
- debounce = a conversation. you wait for the other person to finish speaking before you reply.
- throttle = a drum bit. you only play notes on a simple 4/4 drum bit.
Use cases for debounce:
- Typing. You want to do something after the user stopped typing. So waiting 1sec after the last keystroke makes sense. Each keystroke restarts the wait.
- Animation. You want to shrink back an element after the user stopped hovering over it. Not using debounce might cause an erratic animation as a result of the cursor unintentionally moving between the "hot" and "cold" zones.
Use cases for throttle:
- Scrolling. You want to react to scrolling but limit the amount of calculations made, so doing something every 100ms is enough to prevent potential lag.
- Mouse move. Same as scrolling but for mouse move.
- API calls You want to fire an API call on certain UI events but want to limit the number of API calls you make not to overload your server.
Debouncing allows you to manage the frequency of calls that a function can receives. It combines multiple calls that happen on a given function so that repeated calls that occur before the expiration of a specific time duration are ignored. Basically debouncing ensures that exactly one signal is sent for an event that may be happening several times.
Throttling restricts the frequency of calls that a function receives to a fixed time interval. It is used to ensuring that the target function is not invoked more often than the specified delay. Throttling is the reduction in rate of a repeating event.
Putting debounce and throttle together can be very confusing, because they both share a parameter called delay
.
Debounce. The delay
is to wait till there's no more invokes anymore, then to invoke it. Very much like to close an elevator door: the door has to wait till no one tries to get in before closing.
Throttle. The delay
is to wait with a frequency, then invokes for the last one. Very much like to fire a pistol gun, the gun just can't be fired beyond certain rate.
Let's take a look at the implementation to see in details.
function debounce(fn, delay) {
let handle = null
return function () {
if (handle) {
handle = clearTimeout(handle)
}
handle = setTimeout(() => {
fn(...arguments)
}, delay)
}
}
Debounce, keeps interrupting the timeout until no more interruptions, and then fires fn
.
function throttle(fn, delay) {
let handle = null
let prevArgs = undefined
return function() {
prevArgs = arguments
if (!handle) {
fn(...prevArgs)
prevArgs = null
handle = setInterval(() => {
if (!prevArgs) {
handle = clearInterval(handle)
} else {
fn(...prevArgs)
prevArgs = null
}
}, delay)
}
}
}
Throttle, stores the last call arguments, and sets up an interval to fire until no past fires any more.
Similarities. They both have a delay time, and there's no fire during the delay, especially when there's only one fire. Both do not aggregate past events, so the number of events can be different than the actual fires.
Difference. The delay can be extended in debounce case with repeated events. Whereas the delay in the throttle case is fixed. So in general you get more fires from the throttle than debounce.
Easy to remember. Debounce groups bundle calls into one. Throttle keeps bundle calls within certain frequency.
Updated 1-20-23
Throttle might not need setInterval
, here's a new version I wrote recently which takes care of this
as well.
function throttle(fn, delay) {
let canFire = true
let queue = []
function pop() {
if (queue.length < 1) return
const [that, args] = queue.pop()
fn.apply(that, args)
canFire = false
setTimeout(() => {
canFire = true
pop()
}, delay)
}
function push() {
queue.push([this, arguments])
if (canFire) pop()
}
push.cancel = () => {
queue = []
}
return push
}
Updated 11-09-23
I start to believe throttle is an add-on on top of debounce. Read this https://windmaomao.medium.com/throttle-is-a-debounce-add-on-80d4a6027ad4.
function throttle(fn, delay) {
let h
let queue = []
function pop() {
if (queue.length < 1) return
if (!h) {
const [that, args] = queue.pop()
fn.apply(that, args)
h = setTimeout(() => {
h = null
pop()
}, delay)
}
}
return function push() {
queue.push([this, arguments])
pop()
}
}
Throttling
Throttling enforces a maximum number of times a function can be called overtime. As in "execute this function at most once every 100 milliseconds." Say under normal circumstances you would call this function 1,000 times over 10 seconds. If you throttle it to only once per 100 milliseconds, it would only execute that function at most 100 times
(10s * 1,000) = 10,000ms
10,000ms / 100ms throttling = 100 maximum calls
Debouncing
Debouncing enforces that a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called."
Perhaps a function is called 1,000 times in a quick burst, dispersed over 3 seconds, then stops being called. If you have debounced it at 100 milliseconds, the function will only fire once, at 3.1 seconds, once the burst is over. Each time the function is called during the burst it resets the debouncing timer
source:- throttle and debouncing
Suppose we have a callback function "cb" to be called on event "E". Let "E" getting triggered 1000 times in 1 second, hence there would be 1000 calls to "cb". That is 1 call/ms. To optimize we can either use:
- Throttling: With throttling of (100ms), "cb" would be called on [100th ms, 200th ms, 300th ms, ... 1000th ms]. That is 1 call/100 ms. Here 1000 calls to "cb" optimized to 10 calls.
- Debouncing: With debouncing of (100ms), "cb" would be called only once on [1100th sec]. That is 100ms after the last trigger of "E" which happend on [1000th ms]. Here 1000 calls to "cb" optimized to 1 call.
throtle is just a wrapper around debounce which makes debounce to call passed function
in some period of time, if debounce delays a function call on period of time which is bigger then specified in throtle.
Debouncing and throttling are techniques used to reduce the frequency of actions triggered in response to events. Both techniques accept a delay
in milliseconds not to trigger actions more than once per delay, along with leading
and trailing
boolean options to trigger events at the start (leading edge) and the end (trailing edge) of the delay, respectively.
Debouncing
For each event:
- set the timer;
- if
leading
istrue
, trigger an action at the leading edge if the timer was not already running; - if
trailing
istrue
, trigger an action at the trailing edge if no other event occurs and the action was not already triggered at the leading edge.
Leading-edge debouncing:
--1-------2-3-------4-5-6-------> events
|====| |====| |====|
| | |====| | |====|
| | | |====|
--1-------2---------4-----------> actions
Trailing-edge debouncing:
--1-------2-3-------4-5-6-------> events
|====| |====| |====|
|====| |====|
|====|
-------1---------3-----------6--> actions
Leading-edge and trailing-edge debouncing:
--1-------2-3-------4-5-6-------> events
|====| |====| |====|
| | |====| | |====|
| | | |====|
--1-------2------3--4--------6--> actions
Throttling
For each event:
- set the timer if the timer was not already running;
- if
leading
istrue
, trigger an action at the leading edge if the timer was not already running; - if
trailing
istrue
, trigger an action at the trailing edge if no other event occurs and the action was not already triggered at the leading edge.
Leading-edge throttling:
--1-------2-3-----4-5-6---> events
|====| |====| |====|
--1-------2-------4-------> actions
Trailing-edge throttling:
--1-------2-3-----4-5-6---> events
|====| |====| |====|
-------1-------3-------6--> actions
Leading-edge and trailing-edge throttling:
--1-------2-3-----4-5-6---> events
|====| |====| |====|
--1-------2----3--4----6--> actions
So the key difference between debouncing and throttling is that debouncing sets the timer for all events, which ensures actions are triggered only after a delay without events. In contrast, throttling sets the timer only for events for which the timer was not already running, which ensures actions are triggered only after a delay, regardless of event occurrence.
the lodash Library suggests the following article https://css-tricks.com/debouncing-throttling-explained-examples/ which detailed explain the difference between Debounce
and Throttle
and their origination
Debouncing and Throttling in Javascript
Both functions help to postpone or limit the rate at which some functions are executed. This in turn helps in optimising our web apps.
What is a Throttling?
- Throttling is the way in which we trigger the function within the given amount of time.
- The first request is allowed to pass.
- The original function is executed only once per specified time
Example: The below image depicts the click events which are fired at an interval/delay of 40ms, The events e2,e3, and e4 occurred within 40ms and hence did not get executed.
Code for throttling,
const trottle = function (fn, d) {
let flag = true; // to pass the first event
return function () {
if (flag) {
fn(); // execute the decorative function
flag = false; // block the next fired events
setTimeout(() => {
flag = true; // unblock the next fired events after a specified delay
}, d);
}
};
};
A throttling function is commonly used in resizing or scrolling events.
What is debouncing?
- Debouncing is a way in which we stop the function from being called if it was called recently.
- Only the last request is allowed to pass.
- The original function is executed only if the caller stops calling the decorated function for the specified amount of time.
Example: The below image depicts the click events which are fired only after a delay(100ms) is completed,
Events e1,e2,e3 and e4 were fired by the user but were not successfully executed because the consecutive event occurred within 100ms. (delay between e1 and e2 < 100ms or e2 and e3 < 100ms… etc) Event e4 successfully calls the decorated function because there is a delay of 100ms after it is fired by the user. Code for debouncing:
const debounce = function (fn, d) {
let timer;
return function () {
clearTimeout(timer); // clears/reset the timer if the event is triggered withing the delay
timer = setTimeout(() => { // execute the function
fn();
}, d);
};
};
A debouncing function is commonly used to limit typing(input fields) or clicking events.
Debouncing and Throttling in Action:
Denouncing vs throttling You can visually see the difference here
Supporting documents:
https://www.geeksforgeeks.org/javascript-throttling/ https://www.geeksforgeeks.org/debouncing-in-javascript/
Difference Between throttling and debouncing a function
https://www.youtube.com/watch?v=TBIEArmPywU
How debouncing works in hardware.
Debouncing is the process of removing noise from a digital signal. When a button is pressed, the signal bouncing around can cause the button to be registered as being pressed multiple times. Debouncing removes this noise so that the button is only registered as being pressed once. Picture a ruler being bounced on the edge of a desk, and imagine metal contacts inside a switch bouncing like this.
Better still, look at this diagram, showing the switch noise caused by bouncing.
We use resistors and capacitors of properly calculated ratings to smooth out the signal for n ms.
Explain how signal throttling works in hardware.
Signal throttling is the process of limiting the number of times a signal can be registered. This is often used to prevent a button from being registered as being pressed multiple times in a short period of time.
I prefer the term gating, but that's because I'm into electronic music production.
We open the gate at the end of each throttle period, and allow the signal to pass, and then close the gate again, for the next throttle period.
Explain how debouncing works in software.
Debouncing in software is often accomplished by using a timer. When the button is pressed, the timer is started. If the button is pressed again before the timer expires, the timer is reset. This ensures that the button can only be registered as being pressed once per debounce period.
In many implementations of debounce, we create a debounced version of the function which is embedded in a closure containing a timer (or gate). When the timer delay expires we set it it null again. The actual function only runs when the timer is null. Usually, this means when we first call the debounced function, it'll run once, then subsequent calls to it will be effectively cancelled until the delay time has elapsed.
In some implementations of debounce, while a stream of calls are fired and the timer hasn't expired, the timer will be restarted. Only calling the function after the bouncing has stopped. This is usually called a trailing debounce.
Explain how throttling works in software.
Throttling in software is often accomplished by using a counter. When the button is pressed, the counter is incremented. If the button is pressed again before the counter reaches a certain threshold, the counter is reset. This limits the number of times the button can be registered as being pressed in a given period of time. It's good to visualise this as a pulse or beat, which opens and closes a gate while calls are being sent to the throttle.
Rate limiting is another way to think of a throttle.
Why is this such a common cause of confusion?
In many many use cases a debounce or throttle will get you the results you want, especially if the software implementation you're using allows you to chain, trail, or lead your throttle / debounce.
Still, I hope all the answers here and this one have helped you understand more clearly.
They're very similar.
Debouncing invokes a callback after a delay has elapsed since the last call to the debounced function.
function debounce(callback, delay) {
let timeoutId;
return function() {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => callback.apply(this, arguments), delay);
};
}
function sayHello() {
console.log('Hello!');
}
const sayHelloDebounced = debounce(sayHello, 3000);
sayHelloDebounced();
Throttle invokes a callback on the first call to the throttled function and ignores subsequent calls until a delay has elapsed.
function throttle(callback, delay) {
let callEnabled = true;
return function() {
if (callEnabled) {
callback.apply(this, arguments);
callEnabled = false;
setTimeout(() => callEnabled = true, delay);
}
};
}
function sayHello() {
console.log('Hello!');
}
const sayHelloThrottled = throttle(sayHello, 3000);
sayHelloThrottled();
it’s in fact the way of limiting an event. For example, if you are listening on an event onclick, if it’s regular it will listen to every click you made.
If you use Throttle, it will set an interval between the time you want to listen to event for example listen to one click every second.
Debounce is a more restrictive one, it will only fire itself at the beginning or the ending of an event. For example, you are scrolling and you use Debounce, it will trigger only when you start and you finish to scroll.
As far as I understand, in simple terms Throttling - similar to calling setInterval(callback) for certain number of times i.e calling same function for certain number of times over time on occurrence of event and.. Debouncing - similar to calling setTImeout(callbackForApi) or calling a function after certain time has passed on occurrence of event. This link can be helpful- https://css-tricks.com/the-difference-between-throttling-and-debouncing/
For examples of typical uses cases, I recommend @Guy's answer. But the best way for me to understand these two concepts was to make it about pizzas.
本文标签: javascriptDifference between throttling and debouncing a functionStack Overflow
版权声明:本文标题:javascript - Difference between throttling and debouncing a function - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736673379a1947046.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论