Extending debounce with a maxWait Option

Jamund Ferguson
InstructorJamund Ferguson

Share this video with your friends

Send Tweet
Published 3 years ago
Updated 2 years ago

This lessons builds on Build lodash.debounce from scratch to add support for one of its more interesting options: maxWait. The maxWait option ensures that a debounced method is deferred no longer than the time specified. This is helpful if we need to respond to a long running interaction while it's still in progress.

In this lesson we'll demonstrate how continuously typing into a debounced input field prevents us from logging any input at all. We'll add a maxWait option as a third parameter to our debounce function and set it up using an additional setTimeout call.

Essentially maxWait works by adding a second timer which will fire in the case that the normal debounce timer does not get called. We avoid unnecessarily triggering our debounced function by calling clearTimeout in both of our setTimeout functions to clear out whichever timer didn't just fire. We also need to set the maxTimer variable to null to tell our function it's safe to start a new maxWait timer each time either timer fires.


  • setTimeout returns a timer ID not the actual timer object itself, which is why we have to null it out after we already call clearTimeout
  • If you don't null out maxTimer in your original timer, the maxWait timer will stop triggering after the debounce timer is called the first time. I learned that one the hard way when I first recorded this video.

Jamund Ferguson: [0:00] On the left-hand side of the screen, I have a file named, "debounce-maxwait.js." In it, I have a simple debounce function which is hooked up to the input field on the right. If I pause briefly while typing into the field, its contents are logged.

[0:13] Now, watch what happens when I type continuously into the field. Nothing.

[0:20] To address that, we're going to add a maxWait option to our debounce function, similar to the one found in Lodash. First, use destructured parameter syntax to add a maxWait option. Then, define a maxTimer variable. With that in place below our first timer type, "if (maxWait) { maxTimer = setTimeout( ) }."

[0:40] This is going to look identical to our first timer, except, instead of using "wait" for the amount of time, we're going to use "maxWait." We now have two competing timers, maxTimer and the initial timer.

[0:51] Let's clear the other timer within each of these, clearTimeout(timer), and in the first, clearTimeout(maxTimer).

[1:00] Putting those timers basically ensures that both timers aren't triggered right after another. Now, after you clearTimeout of timer, type, "maxTimer = null." On our if statement we'll say, "if (maxWait && ! MaxTimer.)

[1:15] Essentially, what we're doing here is preventing this timer from being set more than once at a time. Once the timer fires, we'll go ahead and set it to null and then, on the next keyup, it will be set again.

[1:27] We also need to add maxTimer = null in our first timer. That's so that after we clear our timer, we make sure that it's reset again the next time keyup is pressed.

[1:35] With that in place, we now have the ability to ensure that our logging happens even while we're continuously typing. Let's go ahead and update our debounce call now, to add that third option maxWait.

[1:46] We'll pass in a value of 1000 milliseconds, equivalent to one second. As I type in the field, you should see that it continually logs every second.