Throttle vs Debounce on real examples (2024)

Throttle vs Debounce on real examples (1)

What's the difference between throttle and debounce? Both are timing functions that limit the number of function calls sofinding a difference can be challenging. It is for me, more often than I'd like to admit. So I decided to write down acouple of examples. For which interactions we should use the throttle and for which debounce?As a diligent student of User Interactions, I'm more interested in use cases than theory. By reading this post you'llalso learn when not to use none of them because we have better APIs. Interactive examples included! 😍
But first, let's start with a basic question:

What's the purpose of using these timing functions?

The ultimate reason is the performance and protection of resources. That's it. The effect it has on UX is rarely thething that we wanted to do. We have to deal with the consequences of using these functions but if I could, I'd not usethem at all. But we don't have unlimited resources so we have to protect them.

Throttle and Debounce let you call a function fewer times than it would be usually called in a storm of events.Fewer things to process simply mean better performance.

Throttle

Throttle runs a given function just once in a given period. Say you've got 400 events in 2 seconds but you've decidedto throttle that stream and let it be executed just once per second. As a result, your function will be called just twice.Instead of 400!

From a user's point of view, their action will be run every 1 second. No matter how many actions in-between they do.

Debounce

Debounce on the other hand will run a given function after a given period of time will pass without a single event.To put it to the extreme - if you have a constant stream of events that happen every 1 second, and you decided to debouncea function to be run after 2 seconds of "no action" then your function will be never executed.

From a user's point of view, they have to stop doing something for 2 seconds to see the result of their action.

When we should use one or another?

Maybe instead of me saying what I think we could take a look at some real-life examples with three cases:

  • no timing function
  • throttle
  • debounce

and we will get to the answer together by looking at a number of events handled? and the general look&feel?

Searching or typeahead

In functionality like searching or getting hints (typeahead) in most cases, we have to call the server.This kind of functionality happens on every keystroke - not by clicking on the "Search" button. So it will naturallycreate a lot of events.

We have to protect the server and reduce the number of calls. Play with the input below. Just for the sake of simplicity,this search will always show a loading state and "No results".
Observe the number of API calls:

Did you notice that? Debounce seems to be the best in protecting the resources. It waits until a user stops typing.I know everyone is referring to this example as the perfect use of debounce but that's not perfect. It will make yoursearch feel a bit sluggish. No matter how fast your API is, it will always add that extra delay until the API call willbe made (here 400ms). There is a better way for typeahead but I'll write about it in another post. Here let's focus ontiming functions. If you need to aggressively protect the resources I say debounce is good enough.

Save as a user writes

So is debounce the best for typing activities? No. Not always. Imagine you have a rich text editor where a user types somethingand we perform autosave in the background. Debounce's characteristic to wait until the stream of events has stopped for a whilecan be dangerous here.

We can imagine that an impatient user types something and leaves the page before the actual save was performed. With autosaving,we have to use every occasion to store the state (but still protecting our resources).

Play with the textarea below and observe what were the saving states. The server you use can also keep these intermediatestates as points in history to offer a simple revision functionality.

Bio

No timing function

Saved states:

Throttled

Saved states:

Debounced

Saved states:

Hover on the circles that represent the saved state (they will appear after typing). Using throttle seems to be abetter idea here. We do want to protect the server (especially here!) but we don't want to lose any of the user's work either.Timing functions are set to something long (like 2-3 seconds) to not produce too many saves but that harms debounce.It is rarely called and doesn't give us "checkpoints" when typing.

It's not yet ideal but a very good start. To make it better you should learn about canceling requests and leading or trailingedge of a timing function. We'll get back to it. But for now, I say throttle is the way to go for autosaving.

Scrolling interactions

One of the most common examples in timing functions is limiting the number of scroll events. Let's look at how manyevents scroll can generate:

↓ Scroll me ↓

Throttled

Debounced

Okay, so it seems we should do something about it. Scroll naturally generates a massive amount of events. So what kind of interactionswe should consider limiting? I know there are examples of using throttle or debounce to calculate the scroll position toimplement an infinite scroll. That's wrong. You should use Intersection Observer for that. Period.

But we can imagine you'd like to show the progress of scroll a.k.a "how much did user read" functionality. Let's see how thatworks with three approaches (events count is in the brackets):

No timing function (0)

Throttled (0)

Debounced (0)

↓ Scroll me ↓

So we are updating the style of progress bars depending on the scroll position. It's obvious that timing functions introduce somekind of lag here. debounce here is something hard to consider unless you really need to protect resources but why would youimplement such a feature then?

throttle is a bit better to reduce the number of events and still looking quite ok. But to have it really "smooth" we would haveto go down to 16ms of delay. Why 16ms? Because that often you have to refresh an animation to keep 60FPS (1000ms / 60 frames).There is a better API for that and is called requestAnimationFrame.

Play with scroll below. Observe how smooth the animation is and how often it was refreshed.

No timing function (0)

requestAnimationFrame (0)

Throttled (0) [16ms]

↓ Scroll me ↓

Boom 💥 If you are on a fast computer (MacBook?) you won't even notice a difference between "no timing function", "requestAnimationFrame"and "throttled run every 16ms". But trust me, use rAF in case you animate something based on scroll or mouse move.

Here is a screenshot of one of the states I landed in:

On my super-fast computer, the difference between throttle run every 16ms and requestAnimationFrame was super smalland you'd not notice the missing frames in the animation. It can make a difference on slower devices.

Leading and trailing edge

So far, the examples above were using the trailing edge. The edge settings tell if the function should be run at the beginningof the stream of events or the end.

Throttle vs Debounce on real examples (3)

For throttle, the case is easy when picking leading-edge - you want your function to be run immediately after thestream of events occurs and then every 1s for example.

Debounce on the other hand changes its characteristic. The mental model for running debounce immediately is to think about it as a mute.You run something once and ignore all other events until there is a time window (say 1s) of no events. If the events happenafter that we are back to running it only once at the beginning.

Implementation

How to implement debounce and throttle? By importing it from lodash for example 😛 Really. There is no need tore-implement the wheel. Their implementation is great and has additional featuresthat I didn't cover here. Like maxWait. A super-powerful feature that will let you call a function if it didn't happenfor some time (emergency call!). Really great to fight debounce's slugginess.

Summary

The timing functions are great. But for some interactions, we have better APIs these days. Sometimes you might not even see the UI affected,and that's generally what we want.

Protection of resources is important but remember - there is a user at the end. The last thing we want is to screw up theirexperience.

By adjusting timings you can eat a cake and have a cake. Bon appetit! 🍰

How to stay in touch? or comment?

If you'd like to see more content like this, please follow me on Twitter: tomekdev_. I usually write about interfaces in the real life. So where the design meets implementation.
Comments and discussion welcomed in this thread.

Prev

Highlight text in JavaScript

Next

Anchors for headings in MDX

Throttle vs Debounce on real examples (2024)

References

Top Articles
Latest Posts
Article information

Author: Pres. Carey Rath

Last Updated:

Views: 6358

Rating: 4 / 5 (61 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Pres. Carey Rath

Birthday: 1997-03-06

Address: 14955 Ledner Trail, East Rodrickfort, NE 85127-8369

Phone: +18682428114917

Job: National Technology Representative

Hobby: Sand art, Drama, Web surfing, Cycling, Brazilian jiu-jitsu, Leather crafting, Creative writing

Introduction: My name is Pres. Carey Rath, I am a faithful, funny, vast, joyous, lively, brave, glamorous person who loves writing and wants to share my knowledge and understanding with you.