【问题标题】:NW/Node Webkit - Image decodes even if it is already visibleNW/Node Webkit - 图像解码,即使它已经可见
【发布时间】:2016-06-01 01:59:19
【问题描述】:

我目前正在开发基于JavaScript(pure js) 的游戏。游戏包含 5 个大型精灵表(例如 2861 × 768 和 4096 × 4864)。游戏开始时,所有 5 个精灵表都预加载到画布元素中。这 5 个精灵中的三个一起代表一个动画,其中每个精灵包含 75 帧。当一个精灵以动画结束时,我将其隐藏并显示下一个精灵。当第二个精灵完成动画时,我将其隐藏并显示第三个/最后一个。

当第二个或第三个精灵即将显示时,会发生 0.5 s - 1 s 的小延迟。图片正在解码。

这不是第一次发生的事情,而是总是发生的事情。并且该动画每 5 分钟重复一次,并且总是会出现小延迟。

我使用 canvas 元素进行预加载的原因是我认为 WebKit 会丢弃一段时间未使用的解码图像,并且 canvas 元素会阻止 WebKit 从内存中删除它。但这不起作用。

我已经尝试了几乎所有我知道的优化。我什至通过删除后代选择器等重构了我所有的 CSS。

我用来绘制这些动画的渲染器是我自己构建的,它运行良好,所以这不是问题,因为它在 Firefox 中运行良好。

编辑 [2016/03/04]: 我用画布做了一个模式,结果更糟。它滞后了很多。延迟保持不变。仅在 NW 中,该问题在 Chrome 中和 Firefox 中均不存在。

画布模式 - 滞后:

默认(HTML)模式 - 完美运行:

Codepen:我的渲染器http://codepen.io/anon/pen/JXPWXX

注意:如果我用opacity:0.2 而不是opacity:0 隐藏其他元素,则不会发生问题。但是,我不能那样隐藏它们,因为它们仍然可见。它们不应该是可见的。如果我添加 opacity:0.01 它是不可见的,并且问题不会在 Chrome 中发生,但在 NW 中仍然存在。

在 NW 中,当我从 opacity:0.2 切换到 opacity:1 时,正在处理图像解码。 Chrome 浏览器不会发生同样的事情。

我正在使用以下版本:

nw.js v0.12.3
io.js v1.2.0
Chromium 41.0.2272.76
commit hash: 591068b-b48a69e-27b6800-459755a-2bdc251-1764a45

三个图像精灵的大小分别为 14.4MB、14.9MB 和 15.5MB。每个精灵包含 75 帧。

为什么会发生这种情况,我该如何预防?

【问题讨论】:

  • 请注意,这只发生在 Node Webkit 中。它在 Chrome 中运行良好。
  • 你看过垃圾收集器吗?听起来垃圾收集器正在运行,这导致了暂停。无论是您处理画布的方式,还是您的渲染器产生的垃圾比您想象的要多。
  • 你能分享一些代码或把它放在JsFiddle吗?
  • 我同意@Bill 和@AndrewMyers。在可汗学院做了大量的原型设计,我最近发现在那里使用image() 方法时,GC 开销很大。不确定这是由于 Processing.js 库还是可汗学院沙箱的影响,但恢复到纯 JavaScript 后,在小型 100x100 像素putImage() 操作上移除了大约 60MB/s 的 GC,并提供了 2-3 倍的性能提升。将有助于查看处理相关图像的代码部分。
  • @Darko Riđić 让我怀疑的一件事是第 89 行。renderer.rAF = window.requestAnimationFrame(this.render.bind(this)); 绑定应该只做一次,提前。当你调用 bind 时,你正在创建一个新的东西......:D(无论是闭包还是函数的实际新实例,我对函数内部都不是很熟悉)。除非绝对必要,否则我不建议在任何类型的循环中这样做。

标签: javascript performance html5-canvas node-webkit large-files


【解决方案1】:

尝试直接切换到 google-chrome,因为新的 nw 版本可能在 19.04.2016 发布。在那之后,NW 有望跟上 Chromium 的每个版本。

您在 Chrome 中应该不会遇到同样的问题。

【讨论】:

    【解决方案2】:

    鉴于让 Webkit 认为图像仍然显示会使问题消失(如您的不透明度实验所示),我会将其几乎完全移出可见区域,只有一个透明行与视口重叠(使用溢出隐藏)。

    请注意,未打包的 4000x4000 精灵表将使用 64 兆字节的 RAM(每像素 4 字节 (=RGBA)),因此最好确保下一张图像提前“预热”一点,没有一直把它们都打开包装?

    【讨论】:

    • 虽然我已经尝试过类似的方法,但我会再试一次,如果它有效,我会告诉你。谢谢你的建议 :) 但与其做这个 hack,不如改用 Electron 而不是 NW。假设 Electron 可以正常工作。我不会切换到 Electron 并让这个问题得到解决! :D
    【解决方案3】:

    我建议使用idata = ctx.getImageData(0, 0, canvas.width, canvas.height) 从画布中检索数据数组,然后使用ctx.putImageData(idata, 0, 0) 在精灵之间切换,而不是隐藏画布。

    【讨论】:

    • 我仅将画布元素用于预加载。但我会支持画布,“HTML”方式将是一个后备。谢谢你的推荐:)
    猜你喜欢
    • 2013-10-06
    • 1970-01-01
    • 2015-12-02
    • 1970-01-01
    • 2017-02-15
    • 2023-03-24
    • 1970-01-01
    • 2015-01-27
    • 2022-01-24
    相关资源
    最近更新 更多