我们正面临着与mousemove连接的jQuery事件传播性能的问题:
我们有一个屏幕填充画布,需要跟踪用户是否在其上拖动鼠标,因此我们在该对象上添加了一个鼠标移动侦听器,如下所示:
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率导致了很多鼠标移动事件,因此我们更改了上面的代码以应用事件限制,并且每隔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
}
}
});
它就像一个魅力,表现很棒。即使我们只跳过两毫秒的事件。
现在我有两个问题:
我们还有其他位置将mousemove监听器连接到不同的HTML元素,我想将这个手工制作的节流管添加到所有mousemove
处理程序中再次遇到问题。这在jQuery(2.0.3)中以某种方式可行吗?我在jQuery javascript中看到了preDispatch
个钩子,但它们已经在调用fix()后已经使用了一段时间,我也想保存该调用。
我很困惑的事实是,{2}的eventThrottle
已足以获得非常好的表现,所以我添加了一个计数器来查看有多少事件被跳过。令人惊讶的结果是:它只跳过0-1个事件......当油门为100毫秒时,跳过的事件大约为60-70,所以如果每毫秒有少于1个mousemove事件,为什么这个代码毕竟有这样的积极影响吗?
感谢您的任何评论, 克里斯托弗
答案 0 :(得分:3)
2015年底,我遇到了我最终发现的问题。
在我的浏览器应用程序中,我在特定位置绘制了多个不同大小的圆圈,然后拖动整个屏幕的可见部分,仅显示在当前缩放级别可见的整个背景中的圆圈。拖动鼠标会生成一个mousemove事件,该事件会触发对我的渲染例程的调用,从而对每个可见的圆圈进行重新绘制。
在IE 11中对此进行测试时,我发现一旦我在可视区域中有大约100个圆圈,拖动鼠标时渲染变得非常不稳定。分析器表明这几乎完全是由paint()例程引起的。
我的代码已经在库中使用requestAnimationFrame()。有趣的是,在拖动屏幕时,我看到了减速;但如果我只是拖动屏幕并释放它,让图书馆代码继续以减速为动画制作动画,重绘非常顺利。仅在拖动鼠标时才会发生减速。这个问题肯定与mousemove有关。 (稍后再回过头来看。)
我把paint()程序简化为一个简单的填充弧 - 同样的问题。每当我改变缩放级别,然后使用drawImage()将屏幕外画布复制到我的主屏幕时,我尝试将填充的圆圈绘制到离屏画布上 - 这提高了性能,但在IE中它仍然不稳定。然后我尝试使用这种技术将所有圆圈绘制到与我的主要可见窗口大小相同的屏幕外画布,然后更改paint()除了将屏幕外画布复制到我的可见画布之外什么也没做 - 这再次给出了一点改进,但还不够。
然后我尝试在各种浏览器中运行我的应用程序:
IE 11:非常不稳定 Firefox 42:非常不稳定 Chrome 47:在所有缩放级别都非常流畅 Opera 34:在所有缩放级别都非常流畅 Desktop Safari 5.1.7(在PC上):在所有缩放级别上略微不稳定这个问题肯定与mousemove及其如何由不同的浏览器处理有关。
最终我在StackOverflow上发现了这个问题,并且它暗示鼠标本身正在发送如此多的mousemove事件,以至于它正在淹没浏览器快速重绘的能力。我确实有一个具有高事件发生率的现代鼠标。
我尝试将eventThrottle检查添加到我的mousemove事件处理程序中,瞧!成功。我的代码现在可以在所有浏览器上顺利呈现。 (高兴地投票。:))
我想为那些在使用高频鼠标拖动时可能遇到IE和Firefox中糟糕的paint()性能问题的人添加此附加信息。建议的节流鼠标移动事件的解决方案对我有用。
答案 1 :(得分:2)
1 - 有一个节流jQuery插件:https://github.com/cowboy/jquery-throttle-debounce
正如您可以阅读in the examples,您可以替换:
// Bind the not-at-all throttled handler to the resize event.
$(window).resize( handler );
// Bind the throttled handler to the resize event.
$(window).resize( $.throttle( 250, handler ) ); // This is the line you want!
2 - 你想发布你的处理程序的代码吗?
一个盲目的建议:Firebug在FF 24中存在性能问题。您是否尝试将性能与Firebug启用/禁用进行比较?