我们在处理与mousemove相关的jQuery事件传播性能方面遇到了问题:
我们有一个覆盖整个屏幕的画布,并需要跟踪用户是否在其上拖动鼠标,因此我们在该对象上添加了一个mousemove监听器,如下所示:
ourCanvas.on('mousemove',
function(event) {
event.preventDefault();
//our drag code here
}
});
这段代码本来可以正常工作,但是在一个测试系统上,我们发现当前Firefox(24版本)存在严重的性能问题。分析器告诉我们,大部分时间都花费在jQuery.event.dispatch()
函数上(我们尝试了目前最新的jQuery 1.8、1.9、1.10和2.0版本)。
通过使用“jQuery.event.fix()”性能优化,我们成功地减少了在dispatch()函数中所花费的时间。具体可以参考这里:http://bitovi.com/blog/2012/04/faster-jquery-event-fix.html,但是在那个测试系统上的表现仍然远远低于我们的预期。
经过进一步的测试,我成功地将问题定位在了系统上使用的鼠标:它的频率为1000Hz。我们将使用的鼠标改为125Hz,结果表现出色。
我们的假设是,鼠标高的Hz频率会导致产生大量的mousemove事件,因此我们改变了上述代码,应用了事件节流,并且只在每X毫秒调用一次事件处理程序:
var lastMove = 0;
var eventThrottle = 1;
ourCanvas.on('mousemove',
function(event) {
event.preventDefault();
var now = Date.now();
if (now > lastMove + eventThrottle) {
lastMove = now;
//our drag code here
}
}
});
它像魔术一样奏效,性能很棒。尽管我们只跳过了两毫秒的事件。
现在我有两个问题:
我们还有其他位置,在不同的HTML元素上附加mousemove监听器,并且我想将这个自制的限流器添加到所有这些mousemove处理程序中,以避免再次遇到此问题。在jQuery(2.0.3)中,是否有一种好的方式可以实现这一点?我已经看到了jQuery javascript中的preDispatch钩子,但它们已经在调用fix()之后使用了一些时间,我也想节省那个调用。
我对一个2ms的eventThrottle就足以获得非常好的性能感到困惑,所以我添加了一个计数器来查看有多少事件被跳过了。令人惊讶的结果是:它只跳过了0-1个事件...当节流为100ms时,跳过的事件大约是60-70个,那么如果每毫秒少于1个mousemove事件,为什么这段代码仍然具有如此积极的作用呢?
谢谢任何评论, 克里斯托弗
setTimeout()
和clearTimeout()
,但它并不限制实际事件处理。两个副作用:1:我仍然需要调用$.throttle()
而不是$.on()
(在多个开发人员中难以实现)。2:CPU重的jQuery处理开销仍然存在(调用fix()
等)。也许最干净的解决方案是自己覆盖jQuery事件处理函数作为“插件”。@2我们的处理程序更改从运行在requestAnimationFrame
上的循环中访问的一些变量。@Firebug:您对FF24的看法是正确的,只有在禁用Firebug的情况下才进行了测量。 - Christopher Lörken