Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit handling of event to once per X seconds with jQuery / javascript?

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

  1. Does jQuery have an inbuilt way of doing this? I don't see anything in the .on() docs

  2. If not, is there a better pattern for doing this in vanilla JS than I've used in my second jsfiddle example?

like image 663
davnicwil Avatar asked Aug 11 '13 22:08

davnicwil


3 Answers

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

like image 96
Felix Kling Avatar answered Nov 06 '22 20:11

Felix Kling


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/>");  
});
like image 41
c-smile Avatar answered Nov 06 '22 22:11

c-smile


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.

like image 39
disatisfieddinosaur Avatar answered Nov 06 '22 22:11

disatisfieddinosaur