13

嗨我有一个Web应用程序应该能够在智能手机和桌面浏览器上运行。虽然我期待在Iphone这样的小设备上获得一些好奇的行为,但我确信它可以在Android Galaxy Tab上运行,这是Android设备,我现在可以运行测试。某些移动浏览器中的HTML5 Canvas的性能问题。

现在我已经安装了Galaxy Tab的一堆浏览器的测试事情:

  • Android原生浏览器
  • Android版Chrome浏览
  • Android版Firefox

在桌面我已使用

  • 火狐
  • 谷歌浏览器

最后我有一个iPhone来进行测试。

该网站使用HTML5画布进行像素和基于sprite的绘制,没有花哨的转换,过滤器或效果,主要是简单的路径和多边形。我确实倾听触摸事件并使用​​进行正确的重新绘制。

总的来说,应用程序在桌面浏览器上运行良好,它在iOS Safari(iPhone)和Android上的Firefox上也运行良好。然而Android的Native Browser给我带来麻烦。我已经设置好它,以便在javascript无响应时屏幕刷新红色,并且在触摸屏幕时它几乎总是闪烁。

所以我想知道Android Native App和HTML5是否存在任何已知问题。由于本机浏览器的名称不存在,所以很难找到关于此的信息。 对于我可以获得更多信息的任何想法?任何可能导致本机Android浏览器滞后的想法?

有关于这一问题的一些想法:

  • iOS不支持requestAnimationFrame,因此,我超时基于替代取代它。如果我在Android的本地浏览器上使用该替换,问题仍然存在。

  • 我经常使用AJAX(google clojure xhrio)从服务器检索数据。难道数据检索回调阻塞了我的事件管道?

  • 是否已知日志控制台消息(console.log)会减慢应用程序?他们可以触发浏览器重新运行通过DOM树或任何相关的?

+2

我无法回答您的实际问题,但使用控制台可能会消耗大量的内存,具体取决于您如何使用它。特别是如果你记录大对象或记录频繁。 – idbehold 2013-04-24 12:27:56

回答

42

我在很多浏览器中用canvas做了很多实验。我注意到一些性能问题:

首先,你的猜测:

  • 当​​是由浏览器,绘图的东西,应用程序本身能更好地响应支持。使用setTimeoutsetInterval作为回退总是可能的,但您需要注意时间。这robust polyfill可能会有所帮助,但没有什么比本地requestAnimationFrame。

  • 如果每个帧(或几乎)都调用console.log,那么性能会下降。 由于原生Android浏览器没有控制台对象,因此每次调用都会生成一个错误,这也会导致应用程序的运行速度变慢。你可以这样做:

    if(typeof console === "undefined"){ console = {}; }

  • 对于激烈的实时应用web sockets更快然后HTTP请求。不幸的是,旧的原生android浏览器不支持此功能。如果无法使用Web套接字,则应尽量减少http请求。

注:Chrome支持Android的大多数HTML5功能在这里引用,包括​​和websockets

的更多信息:

  • 使用2D fillText上下文太贵了,但在某些浏览器,这是更糟糕的绘制文本。在另一个画布中预先呈现文字或使用位图字体。 (在原生的Android浏览器中,替换filltext绘制预渲染素材后,在我制作的一些游戏中,性能从10-15 FPS提高到30-45 FPS)。

  • 避免缩放和旋转上下文,因为它们还会导致性能下降。如果您只需缩放或旋转一个精灵一次,也可以使用预渲染。

  • 您需要尽量减少实时绘图。预先渲染你的东西,只要你可以。重新绘制只更改并需要更新的内容。

  • 试着写memory efficient和垃圾回收器友好代码。

还有很多事情要做。我刚才列举了一些。

提示:对功能进行一些压力测试,您不确定它们是否是性能杀手,并捕获基准测试结果。

在移动应用程序中,特别是实时应用程序,如果只是过度优化或增加一点内存,所有优化都是不受欢迎的。

欲了解更多信息,请访问以下链接:

还搜索性能Posts & Tutorials

编辑
jsfiddle code snippet显示了一些东西盖在这个答案,并提供一个粗略的FPS计数器基准。编辑这个小提琴你自己并检查出来。

+4

真正有帮助和有见地的答案。非常感谢;) – wirrbel 2013-04-26 12:18:09

+0

在预渲染中使用额外的canvas els时,确保它们的内容不被剪切,例如,旋转文字时。在这种情况下,您可以在预渲染画布上翻译内容,然后在使用drawImage使用画布时将其移回:'preRenderCtx.translate(100,100); preRenderCtx.rotate(旋转); preRenderCtx.fillText(char,0,0); context.drawImage(preRenderCanvas,x-100,y-100);' – 2018-02-13 13:47:23

0

根据您所绘制的内容,使用Html5画布的最常见的性能改进策略是利用图层(即多个画布)并仅更新需要重绘的图层,而不是在每个动画帧上重新绘制整个图层。你可以自己推出类似的东西,或者你可以使用类似于这是一个轻量级的Html5画布框架,可以实现点击检测,分层,缓存,像素比例支持,下载等外设。您可以这样做:

var wrapper = new Concrete.Wrapper({ 
    width: 500, 
    height: 300, 
    container: el 
}); 

var layer1 = new Concrete.Layer(); 
var layer2 = new Concrete.Layer(); 

wrapper.add(layer1).add(layer2); 

// something happens which requires you to redraw layer2, but not layer1... 
layer2.sceneCanvas.context.fillStyle = 'red'; 
layer2.sceneCanvas.context.fillRect(0, 0, 200, 100); 
相关问题