Lower the frequency of Javascript event polling
Asked Answered
M

6

8

How do you lower the frequency of Javascript event polling? The events I'm concerned about are onResize and onScroll. These events may be triggered dozens of times per second when someone resizes their browser or scrolls down, respectively. I'd like these events to happen only once every 500 ms so I don't have to spend hours optimizing my event handlers and making sure they don't leak memory.

Meyer answered 7/12, 2010 at 2:4 Comment(0)
F
12
var resizeTimeout;

window.onresize = function() {
    if (resizeTimeout) {
        clearTimeout(resizeTimeout);
    }
    resizeTimeout = setTimeout(function() {
        // Do it!
    }, 500);

});

This will trigger the setTimeout() function ~500ms after the person has finished resizing.

The onscroll version is very similar :)

Fettling answered 7/12, 2010 at 2:8 Comment(4)
this one will not fire every 500 ms, it will only fire 500 ms after you stop/pause resizingMaimaia
+1 beat me to it. Remember to include a check for resizeTimeout since it'll be undefined the first time round.Dissimilitude
@Maimaia Yeah, I know, I mentioned that. It may still be suitable for the OP.Fettling
@alex, calling a handler after the resize pauses/stops is different, though, than calling a handler "live" but at a less zealous pace than the browser tends to fire the event.Emogene
M
5

You can't really control how frequently the event fires, you can do something like remember the time of first event firing, then on each consequent one you check if it's more than 500 ms from first one - if yes, you proceed with the event handler, otherwise you just exit the event hanlder

Maimaia answered 7/12, 2010 at 2:8 Comment(2)
+1 for this answer then, this is probably what the OP wants. However, you need some additional logic to handle the last resize event.Dissimilitude
I think the timer solution will take care of the last resize event, so the real solution would be some combination of the twoMaimaia
A
1

At the beginning of your handler, check to see if 500ms have passed since the last one, and just return if not.

Adenosine answered 7/12, 2010 at 2:10 Comment(0)
I
1

You can't prevent these events from firing. They always do. What you want to do is stop listening immediately, then handle the event to avoid repetition. Then the entire handler is set up again after setTimeout. No more recursion happens unless somebody resizes the window. I use 5000ms here as it's easier to see it working in the console. You shouldn't see more than one spam in the FF console every 5 seconds even if you resize like a spaz.

(function staggerListen(){
  window.onresize = function(){
    window.onresize = false;
    console.log('spam');
    setTimeout(staggerListen,5000);
  };
})()

Using logic to decide whether to do anything every time the handler fires is still technically firing a handler and an if statement + lookup. That can get heavy.

Ivo answered 7/12, 2010 at 3:19 Comment(1)
Wow. I'm not sure what the overhead is for dynamically adding/removing the listener callback, but +1 for being tricky, anyhow. :)Calamity
S
1

check the underscore debounce function

Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving. For example: rendering a preview of a Markdown comment, recalculating a layout after the window has stopped being resized, and so on.

Example:

window.onscroll = _.debounce(
  function() {
      // do something
  }, 500, false
);
Stronski answered 3/12, 2012 at 11:17 Comment(0)
B
0

I used to make it like on the accepted answer but the problem is, it only triggers after the timeout specified. I wanted a solution that handles the resize right away, the first time. Here is what I ended up doing.

var _resize_is_busy = false;
var _resize_scheduled = false;
var _resize_precision = 100;

// This register for window resize events. No need to change anything.
$(window).resize(function () {

    if (!_resize_is_busy) {

        // call the scheduler who will do the work and set a timer to
        // check of other resizes occured within a certain period of time

        _resize_scheduler();
    }
    else {

        // the resizer is busy, i.e. a resize have been handled a little
        // time ago and then the scheduler is waiting some time before 
        // handling any other resize. This flag tells the scheduler that
        // a resize event have been receive while he was sleeping.

        _resize_scheduled = true;
    }
});

// This is the scheduler. No need to change anything.
var _resize_scheduler = function () {

    _resize_is_busy = true;
    _resize_scheduled = false;

    setTimeout(function () {

        _resize_is_busy = false;

        if (_resize_scheduled) 
            _handle_resize();

    }, _resize_precision);

    _handle_resize();
}

var _handle_resize = function () {

    console.log('DOING ACTUAL RESIZE');

    // do the work here
    //...
}

I hope this will help.

Botanize answered 18/5, 2017 at 13:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.