问题
I'm trying to figure out a clean way to aggregate mousemove events so that I ensure my code gets called, but only once every 250-300 milliseconds.
I've thought about using something like the following, but was wondering if there was a better pattern, or something jQuery provides that will do the same thing:
var mousemove_timeout = null;
$('body').mousemove(function() {
if (mousemove_timeout == null) {
mousemove_timeout = window.setTimeout(myFunction, 250);
}
});
function myFunction() {
/*
* Run my code...
*/
mousemove_timeout = null;
}
EDIT: The accepted answer below would work perfectly for this situation, however, I found that the mousestop()
functionality provided in the answer actually eliminated my need for the aggregation, so if you're reading this question and looking for an answer, see if the mousestop plugin is what you really need!
回答1:
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;
});
回答2:
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)
回答3:
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() {
//...
}
回答4:
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);
})
回答5:
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);
};
};
回答6:
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.
回答7:
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();
回答8:
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);
}
});
回答9:
Why not use setInterval() instead of timeouts?
来源:https://stackoverflow.com/questions/4648444/jquery-fire-mousemove-events-less-often