15

嗨,我有一个应该能够在智能手机和桌面浏览器上运行的 Web 应用程序。虽然我期待在像 Iphone 这样的小型设备上会出现一些奇怪的行为,但我非常有信心它会在 Android Galaxy Tab 上运行良好,这是我目前可以运行测试的 Android 设备。

现在我在 Galaxy Tab 上安装了一堆浏览器来测试:

  • 安卓原生浏览器
  • 安卓版 Chrome
  • 火狐安卓版

在我用过的桌面上

  • 火狐
  • 谷歌浏览器

最后我有一个 Iphone 来测试。

该网站使用 HTML5 画布进行基于像素和精灵的绘图,没有花哨的转换、过滤器或效果,主要是简单的路径和多边形。我确实会听触摸事件并requestAnimationFrame用于适当的重绘。

总体而言,该应用程序在桌面浏览器上运行良好,在 iOS Safari (iPhone) 和 Firefox-on-Android 上也运行良好。然而,Androids Native Browser 给我带来了麻烦。我已经设置了它,以便当 javascript 没有响应时屏幕会变成红色,并且在触摸屏幕时它几乎总是会闪烁。

所以我想知道Android Native App和HTML5是否存在任何已知问题。由于本机浏览器的名称不存在,因此很难通过谷歌搜索相关信息。对我有什么想法可以在哪里获得更多信息?有什么想法可能导致本机 Android 浏览器滞后?

关于这个问题有几个想法:

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

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

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

4

2 回答 2

44

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

首先,关于你的猜测:

  • requestAnimationFrame浏览器支持时,绘图内容和应用程序本身的响应速度更快。始终可以使用setTimeoutorsetInterval作为后备,但您需要注意时机。这个强大的 polyfill可能会有所帮助,但与原生 requestAnimationFrame 相比没有任何帮助。

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

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

  • 对于密集的实时应用程序, Web 套接字比 http 请求更快。不幸的是,旧的原生 android 浏览器不支持此功能。如果无法使用 Web 套接字,则应尽量减少 http 请求。

注意: Android 版Chrome支持此处引用的大多数 HTML5 功能,包括requestAnimationFramewebsockets.

更多信息:

  • 使用上下文 2d 绘制文本fillText太昂贵了,但在某些浏览器中,这甚至更糟。在另一个画布中预渲染您的文本或使用位图字体。(在原生 Android 浏览器中,在将filltext绘图替换为预渲染后,在我制作的一些游戏中,性能从 10-15 FPS 增长到 30-45 FPS)。

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

  • 您需要最小化实时绘图。尽可能预渲染你的东西。仅重绘已更改且需要更新的内容。

  • 尝试编写内存高效且垃圾收集器友好的代码。

还有很多事情要做。我只是列举了一些。

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

在移动应用程序中,特别是实时应用程序中,所有优化都是受欢迎的,无论是过度优化还是内存增加。

欲了解更多信息,请点击以下链接:

还可以在Posts & Tutorials中搜索性能。

编辑
这个jsfiddle 代码片段显示了这个答案中涵盖的一些内容,并提供了一个粗略的 fps 计数器来进行基准测试。自己编辑这个小提琴并检查一下。

于 2013-04-25T06:47:59.843 回答
0

根据您所绘制的内容,Html5 画布最常见的性能改进策略是利用图层(即多个画布)并且只更新需要重绘的图层,而不是在每个动画帧上重绘整个内容。你可以自己滚动这样的东西,或者你可以使用http://www.concretejs.com/之类的东西,这是一个轻量级的 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);
于 2016-04-02T22:07:24.857 回答