Understanding event throttling
Seb Toombs
Mar 22 2020 ()
5 min read
Event throttling, what on Earth is it, how does it work, and why do you care?
Ok, I apologise that this post isn't so much something you can crack open in a project and get your teeth into. It's more of a concept, a lesson. But it's something you might come across and it is relevant to frontend Javascript. It's probably relevent in quite a few places.
We're going to talk about event throttling or more accurately, throttling event handlers, as we don't actually have any control over the events themselves.
What's an event
We're going to talk about events in the context of frontend web development. In this context, events that we might want to throttle include things like mouse move, scroll or mobile specific events like touch events.
Browsers will listen to all kinds of events that are provided, either by the user or some other system, and allow you to attach your own listeners via javascript to run various actions when these events occur.
When we bind a function to an event, it's called an event handler. The event happens, our event handler runs (essentially). In code, that often looks like this;
// For example, listen to scroll events
const onScrollHandler = () => {
console.log('Window scrolled!');
}
window.addEventListener('scroll', onScrollHandler);
Why would I want to throttle an event handler
Good question. Let's take the example above, and let's say you're doing some complicated maths every time the event handler is fired, instead of just logging to the console.
Now, how the event loop works is (loosely) that the browser will call your event handler pretty much as often as it can while the event/s triggering it are happening.
You're listening to scrolling? And the user is scrolling? Cool, the browser is calling your event handler many, many times per second (or as many as it can). See where I'm going with this?
If you stick some complicated, memory intensive, long running process in your event handler, what happens? Every time the browser calls it, it starts chewing through the complicated stuff. This takes a while, probably longer than the time it takes for the browser to call the function again. The browser kicks off the event handler again. And so on. Eventually the browser crashes (maybe).
What can I do?
I mean, I really set myself up for this one; throttle the event handler!
Throttling our event handler involves creating a function to wrap our event handler and only allow it to be invoked once per some time period. For example we only allow our function to run once every 100ms at most.
This means our code has time to complete, and we're not chewing up CPU by running our function an unneccessary number of times. (For reference, if you're updating the DOM, the human eye can only update 60 times per second* which is roughly every 16 ms.)
* not entirely true, but for the purposes of this article let's assume it is.
Throttling explained
So throttling ensures that our function executes once, and only once, per the time period we specify.
A good example is from this article by David Corbacho on CSS tricks about throttle vs debounce, using an infinite scrolling element.
As the user is scrolling down the page, we need to know how far from the bottom the user is. To do this we need to listen to the on scroll event. We don't want to miss it though, so we need our function to execute at least once per our window.
To achieve this we need our function to execute on both the leading and trailing edge of our throttle period.
What does this mean? If we consider our incoming events (in this case scroll events) as signal pulses, and plot them against time, we get the below figure.
When the first event occurs, it starts our throttle period. This is our leading edge, as it starts the throttling.
Any events that occur for the next 100 ms are effectively ignored.
When our period is over (after 100 ms), this is our trailing edge.
So if we specify that we want our function to execute once per 100 ms, on the leading edge, it will run at the first event, and not for the next 100 ms.
If we specify that we want our function to execute once per 100 ms, on the trailing edge, it will run 100 ms after the first event.
If we specify that we want to throttle our function to 100 ms but execute on the leading and trailing edge, it will run on the first event, and not again until the end of the 100 ms.
That's throttling
Hopefully you've got a somewhat better understanding of how to throttle a javascript event handler, why you might want or need to do it, and how to set it up.
If there's anything unclear, or you think I should explain some bits better, please reach out to me on twitter @bafffledbasti.
One last pro-tip to leave you with: I wouldn't recommend writing your own throttling function. Trust me, it's a recipe for failure. Use something like lodash - it's tried and tested and just works.