Throttle and Debounce
In this article, we're going to talk about two of the most important functions in frontend development, throttle and debounce.
In this article, we're going to talk about two of the most important functions in frontend development, throttle and debounce.
Both of these functions are commonly used to deal with situations where a user is causing an event handler to fire on repeat and we want to slow down the underlying function call. Think scroll handlers, keyboard events, or even just clicking a button rapidly.
Throttle
Throttle is a higher order function that takes a function and a timeout and only allows that function at most once per the amount of time specified.
Before we use throttle. Let's start with an example.
In this example above we have a piece of state numSpells
and a function that can increment this state castSpell
. We have a button we can click that increments numSpells
. You can play with it below.
Now you can click this button as quickly as you want and it will increment the number of spells cast. Now spells take some time to recharge, so we can use throttle to slow down the user.
We now have a button that call castSpellThrottled
when the user clicks it. Try it out below.
Now that we understand what it does, lets dive into the source of throttle.
What's going on here? Throttle is a function that takes a function and a timeout. Throttle returns a new function that forms a closure around the original one.
We keep track of a boolean
called ready
that stops the inner function from firing unless the timeout has elapsed. If we fire the function we also fire a timeout that will set ready
to true when the timeout has elapsed. Pretty cool, huh?
Debounce
Debounce is a bit different from throttle. With throttle we slow down function calls as they happen, with debounce we don't fire at all until the user has stopped calling it.
This is really useful if you want to perform a computation or hit an api when the user is done typing or done scrolling. Let's play with another example.
You'll notice, you can click Cast Spell Debounced as many times as you'd like, but it will only fire after you've stopped clicking it. The source for this is similar to the previous component.
Now that we know what it does, let's see how it works.
While the last one relied on a simple boolean, with this one we need to maintain access to the timer. We do this because we need to clear the previous timeout every time the function gets called again. We then set a new timeout to call the inner function.
Real World
Now these implementations of throttle and debounce were both very naive. If you take a look at the lodash source you can see a much more advanced version of debounce that considers things like calling the function before or after we set the timeout.
It also allows fancy things like a maxWait
and a cancel
. They even implement throttle with debounce.
Wrapping Up
Hopefully you've learned a bit about debounce and throttle. For more real world code, check out some of my other articles Functional Programming Fundamental or Map, Filter, Reduce.
If you're looking for more abstract stuff check out What the Functor? and Mary Had a Little Lambda.
Also if you feel the need to buy me a drink you can do so here or follow me on twitter @MatthewGerstman.