For a rapidly-firing keypress
event, I want to limit the handling of the event to a maximum of once per X seconds.
I'm already using jQuery for the event handling, so a jQuery-based solution would be preferred, though vanilla Javascript is fine too.
This jsfiddle shows keypress firing rapidly without any limiting on the handling
This jsfiddle implements limiting the handling to once per 0.5 seconds in vanilla JS using setTimeout()
My question is
Does jQuery have an inbuilt way of doing this? I don't see anything in the .on()
docs
If not, is there a better pattern for doing this in vanilla JS than I've used in my second jsfiddle example?
Does jQuery have an inbuilt way of doing this?
No.
If not, is there a better pattern for doing this in vanilla JS than I've used in my second jsfiddle example?
Instead of using setTimeout
and flags, you can keep track of when the handler was called the last time and only call it after a defined interval has passed. This is referred to as throttling and there are various ways to implement this.
In its simplest form you just have to ignore every call that is made within the time of lastCall + interval
, so that only one call in every interval occurs.
E.g. here is a function that returns a new function which can only be called once every X milliseconds:
function throttle(func, interval) {
var lastCall = 0;
return function() {
var now = Date.now();
if (lastCall + interval < now) {
lastCall = now;
return func.apply(this, arguments);
}
};
}
which you can use as
$("#inputField").on("keypress", throttle(function(event) {
$("div#output").append("key pressed <br/>");
}, 500));
DEMO
As Esailija mentions in his comment, maybe it is not throttling that you need but debouncing. This is a similar but slightly different concept. While throttling means that something should occur only once every x milliseconds, debouncing means that something should occur only if it didn't occur in the last x milliseconds.
A typical example is the scroll
event. A scroll event handler will be called very often because the event is basically triggered continuously. But maybe you only want to execute the handler when the user stopped scrolling and not while he is scrolling.
A simple way to achieve this is to use a timeout and cancel it if the function is called again (and the timeout didn't run yet):
function debounce(func, interval) {
var lastCall = -1;
return function() {
clearTimeout(lastCall);
var args = arguments;
var self = this;
lastCall = setTimeout(function() {
func.apply(self, args);
}, interval);
};
}
A drawback with this implementation is that you cannot return a value from the event handler (such as return false;
). Maybe there are implementations which can preserve this feature (if required).
DEMO
I would do that event throttling as simple as this:
$("#inputField").on("keypress", function(event) {
var now = Date.now();
var nt = $(this).data("lastime") || now;
if( nt > now ) return;
$(this).data("lastime", now + 500);
$("div#output").append("key pressed <br/>");
});
Record when the last time you processed the event was, and each time you get an event, do a check to see if the interval you want has elapsed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With