【问题标题】:Javascript runs slowly in Safari / iPad2 after loading 200mb worth of new Images(). Why might this be?加载 200mb 的新图像()后,Javascript 在 Safari / iPad2 中运行缓慢。为什么会这样?
【发布时间】:2012-05-21 21:19:28
【问题描述】:

有谁知道为什么将大量外部 JPG/PNG 图像加载到 HTML5 Image() 对象中会影响 Javascript 性能,总共大约 200Mb-250Mb。性能似乎也受到缓存的影响。 IE。如果先前浏览的缓存已满(-ish),则当前站点的性能会大大降低。

有2个说我可以粗略地解决它。

  1. 手动清除缓存。
  2. 最小化浏览器,等待大约 20 秒,然后重新打开浏览器,之后 iOS/浏览器已回收内存并正常运行 JS。

我原以为 iOS 会回收运行当前任务所需的内存,但似乎并非如此。另一种解决方法是将 200Mb 的“缓存清除”图像加载到 Image() 对象中,然后通过设置 src = "" 将其删除。这似乎确实有帮助,但它不是一个优雅的解决方案......

请帮忙?

【问题讨论】:

  • 完全是猜测,但可能是因为你刚刚占用了 iPad 的一半物理内存。这是一个非常受限制的设备,无论如何,沉重的页面都会磨损。 IMO 嵌入式系统技巧虽然可能不雅,但却是唯一真正的解决方案。
  • 你不能减少图片的大小或数量吗?
  • @Mikey:是的,我可以减少图像数量,但我仍然会遇到问题,因为分配给以前站点的缓存会翻转并影响我的站点/代码。问题是,它是一个非常依赖 gfx 的网站,目前只能进行优化。
  • 我希望这是个玩笑...单页上有 200MB 的图像?真的吗?
  • Image() 对象是否存储在未压缩的位图中或其他内容中?

标签: javascript ios performance html caching


【解决方案1】:

首先阅读优秀的post on LinkedIn Engineering blog。仔细阅读并检查是否有一些您也可以在您的应用程序中尝试的优化。如果您尝试了所有这些方法,但仍未解决您的性能问题,请继续阅读。


我假设您的页面上有一些图片库或杂志风格的内容区域

将此图像区域放在单独的iframe 中怎么样?那么你可以做的是:

  1. 有两个 iframe。只有一个应该及时可见并处于活动状态。
  2. 将图像加载到第一个 iframe。跟踪加载图像的大小。如果精确的尺寸跟踪很困难

    numberOfLoadedImages * averageImageSize

    可能是一个很好的近似值。

  3. 随着该数字接近某个阈值,开始将当前可见的内容预加载到第二个 iframe 中。
  4. 翻转 iframe 的可见性,使第二个变为活动状态。
  5. 清除第一帧的内部内容。
  6. 根据需要重复整个过程。

我不确定这是否适合你,但我希望 iPad 上的 WebKit 引擎能够独立清除帧的内存。


编辑:原来你在写游戏。

如果这是一款游戏,我假设您希望同时在屏幕上显示许多游戏对象,并且您将无法简单地卸载其中的某些部分。以下是针对该案例的一些建议:

  1. 不要将 DOM 用于游戏:它太占内存了。幸运的是,您已经在使用 canvas
  2. 精灵您的图像。图片精灵不仅有助于减少请求的数量。它们还可以让您减少 Image 对象的数量并降低每个文件的开销。在 IE blog 上阅读有关使用 sprite 制作 canvas 动画的信息。
  3. 优化您的图像。有几种图像文件大小优化器。 SmushIt 就是其中之一。试试你的图像。注意this great series by Stoyan Stefanov at YUI blog 中讨论的其他技术。
  4. 尝试矢量图形。 SVG 很棒,canvg 可以在画布上绘制它。
  5. 尝试简化您的游戏世界。也许有些背景对象不需要那么详细。或者,也许您可​​以为他们使用更少的精灵。或者,您可以为同一组的不同对象使用图像过滤器和蒙版。正如 Dave Newton 所说,iPad 是一款非常受限制的设备,您很有可能会获得质量相对较低的精灵。

这些都是与减少您必须加载的数据相关的建议。其他一些可能对您有用的建议。

  1. 预加载您将需要的图像并卸载您不再需要的图像。如果您的游戏有“关卡”或“任务”,则加载仅当前游戏所需的精灵。
  2. 尝试先加载“流行”图像,然后在后台下载剩余的图像。您可以为此使用单独的<iframe>,这样您的主游戏循环就不会被下载中断。 您也可以使用cross-frame messaging 来协调您的下载框架。
  3. 您可以将最受欢迎的图片存储在localStorageApplication CacheWebSQL。他们每个可以为您提供 5 mb 的存储空间。这对您来说是 15 兆 的持久缓存。请注意,您可以将类型化数组用于localStorageWebSQL。另请注意,Application Cachequite hard to work with
  4. 尝试将您的游戏打包为PhoneGap 应用程序。通过这种方式,您可以避免用户在玩游戏之前下载大量数据。单次下载 200 兆只是为了打开一个页面,实在是太多了。大多数人甚至都不会费心等待。

除此之外,您最初建议用图像覆盖缓存实际上是有效的。只是不要马上去做。探索减少游戏下载大小的可能性。

【讨论】:

  • 它适用于作为战斗一部分的 HTML5 游戏,因为所有(大约 200 个)gfx 资产在游戏初始化之前加载到内存中。一切都呈现在 Canvas 元素上。通过简单地在“drawImage()”例程中包含或省略,可以使事物可见或不可见
  • 感谢 Andrew,您在那里提出了一些有趣的观点。 spritesheet 方法是我已经想到但尚未尝试过的方法。那将是我尝试的下一件事。它很棘手,因为 iPad 会产生看似不可预测且未记录的结果。我面临的核心问题是为什么在使用一定数量的内存时会影响 JavaScript 的性能。我将进一步调查并发布任何发现。干杯
  • 有一次我注意到直接在画布上调整图像大小会显着影响性能。为了解决这个问题,我将调整大小的图像预渲染到他们自己的画布上,随时可以使用。
【解决方案2】:

我设法通过将当前不在视口中的所有图像设置为 display:none 来减少影响。虽然这是使用背景图像,但我还没有测试超过 100Mb 的图像,所以不能说这是否真的有帮助。但绝对值得一试。

【讨论】:

  • 不幸的是,我不能使用 CSS 属性,因为我没有使用任何 DOM 对象(画布包装器除外)。绝对所有内容都呈现在 Canvas 元素上。根据游戏的状态,JS 决定将哪个“预渲染”库项目放置到画布上,然后使用“drawImage()”进行绘制。这就是为什么所有的 gfx 都需要在游戏开始前预加载和预渲染,因此需要如此大的内存分配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-20
  • 2011-08-05
  • 2011-10-18
  • 1970-01-01
  • 2021-05-03
相关资源
最近更新 更多