jQuery: Fire mousemove events less often

徘徊边缘 提交于 2019-12-03 03:21:00

Your code is fine except that you should clear the timeout before setting it to null or it might leak:

window.clearTimeout(mousemove_timeout);
mousemove_timeout = null;

As an alternative you could use mousemove/mousestop in conjunction with window.setInterval

var timer = null;
var isIntervalSet = false;

$('body').mousemove(function() {
    if (isIntervalSet) {
        return;
    }
    timer = window.setInterval(function() {
        /*
        * Run my code...
        */    
    }, 250);
    isIntervalSet = true;
}).mousestop(function() {
    isIntervalSet = false;
    window.clearTimeout(timer);
    timer = null;
});

After I tried the solution in the accepted answer, I found out that if the mouse keep moving constantly, especially in circular motion, mousemove() event is fired continuously, but the mouse coordinates remain the same. So I came up with a simpler solution which eliminates mousestop() and setTimeout.

$("body").mousemove(function (e) {
        if (enableHandler) {
            handleMouseMove(e);
            enableHandler = false;
        }
});

timer = window.setInterval(function(){
    enableHandler = true;
}, 100);

This will correctly call handleMouseMove() approximately every 100ms. (Note that I said approximately because time delays and intervals in JavaScript is not real-time guaranteed)

A solution and a question^^

What about this approach without a global var. Is that a suitable solution?

$(function() {
    $("#foo").mousemove((function() {
        var timer = null;

        return function() {
            if (timer !== null) {
                window.clearTimeout(timer);
            }
            timer = window.setTimeout(foo, 250);
        };
    })());
});

function foo() {
    //...
}

A simple way of gettin the mouse position in a custom period of miliseconds

var timer;
var refresh_time = 50;
var x = 0;
jQuery('body').mousemove(function(evt) {
  if (timer)
    clearTimeout(timer);
    timer = setTimeout(function(){
      var mouse_x = evt.clientX;
      if(mouse_x != x){
        x = mouse_x;
        console.log('mouse is on a new x position' + x);    
      }
    }, refresh_time);        
})

You seek code Throttling / Debouncing.

http://benalman.com/projects/jquery-throttle-debounce-plugin/ http://drupalmotion.com/article/debounce-and-throttle-visual-explanation

Sample from underscore.jS

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

I know I'm a little late to the party, but it might be of use to people visiting this thread, here is my 2 cents.

Using the modulus operator and simple number increments, you can throttle the firing rate of your function with minimal performance hit, like so;

var fired = 0;
$('#element').on('mousemove', function(){
   fired++;
   // Fire 5x less than usual
   if(!(fired % 5) || fired == 1) yourFunction();
})

Additionally, if you're afraid to hit the max integer limit, you can reset the fired variable every X thousand hits (again, using the modulus operator) or by using the mouseout event.

This was a really interesting question. I found a less hackish way to do this on, and you can check out this live demo of the following snippet:

({
    event: null,
    interval: null,
    init: function(){
        var self = this;
        $(document).bind("mousemove", function(e){self.event=e;});
        this.interval = setInterval(function(){
            /** do what you wish **/
            console.log(self.event);
        }, 250);
        return this;
    },
    stop: function(){
        $(document).unbind("mousemove", this.event);
        clearInterval(this.interval);
    },
}).init();

You can save a few lines by using the timeout to null the timer:

var paused = null;

$("body").mousemove(function (e) {
    if (!paused){
        /** your code here **/
        paused = setTimeout(function(){paused=null}, 250);
    }
});

Why not use setInterval() instead of timeouts?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!