Watching users double-click a form button always makes me cringe. Worse: knowing that AJAX is firing with each click. Instead if flooding our server with AJAX requests it would be nice to limit how frequently the click handler runs. Fortunately, libraries like Underscore.js have wonderful functions like throttle
and debounce
do just that.
But which do you use?
A quick JavaScript example
The documentation for throttle
indicates the passed function will be called at most “once per every wait milliseconds”, whereas debounce
will execute the function on the trailing/leading edge of the wait period. Personally, I find this hard to understand without an example. Check out this jsFiddle that visually explains the difference:
The top set of “lights” uses throttle
. Click on the top example once and watch the first light show up, then really hammer on that mouse button. You’ll see the green lights go on one-by-one, but there will always be at least a 1-second wait between each. throttle
doesn’t stop the click handler from running, rather it’s just limiting it to run once a second. The gotcha: subsequent clicks get rolled into 1 click event that will fire. That leads to the “laggy” second light turning on.
The bottom set of “lights” uses debounce
with a third parameter set to true
so it fires its event on the first click. Try hammering your mouse button again and notice no matter how many times you click the additional lights won’t turn on. Why? Subsequent clicks are filtered out and they reset the wait time. The gotcha: the user still has to wait a whole second for the handler to return to firing events.
Other ways to defeat that secondary click … or not
There are some other ways to defeat a secondary click which can be a bit obtuse:
- jQuery’s one(): If you really only want something to fire once and only once
one
is great. (Underscore.js also hasonce
.) However, if you still plan on reusing the targeted element you’ll have to rebind your event handler. - Ignore the built-in
dblclick
event: You could prevent the element’sdblclick
, but the originalclick
event still fires. This doesn’t really work to throttle the clicks.
Other lessons we learned
Through testing we have found that debounce
works really well with a wait time around 500ms.