NW/Node Webkit - 即使图像已经可见,仍会解码

19

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

在显示第二或第三个精灵之前,会出现0.5秒至1秒的小延迟。这是因为图片正在解码。

这不仅仅是第一次发生,而是每5分钟重复的动画,小延迟总是发生。

我使用canvas元素进行预加载的原因是,我认为WebKit将删除一段时间未使用的解码图像,而canvas元素将防止WebKit将其从内存中删除。但那行不通。

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

我用来绘制这些动画的渲染器是我自己构建的,它在Firefox中运行得非常好,所以那不可能是问题所在。

编辑[2016/03/04]: 我用canvas模式进行了测试,结果更糟糕。它经常卡顿。延迟仍然存在。在NW中,这个问题在Chrome和Firefox中都不存在。

Canvas模式-卡顿: enter image description here

默认(HTML)模式-完美运行: enter image description here

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

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

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

我使用以下版本:

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帧。

为什么会出现这种情况,我该如何防止呢?


1
请注意,这仅在Node Webkit中发生。在Chrome中它运行得非常好。 - Darko Riđić
1
你看过垃圾回收器吗?听起来像是垃圾回收器在运行,导致了暂停。可能是你处理画布的方式或者你的渲染器创建的垃圾比你想象的要多。 - Bill
3
你能分享一些代码或将其放在 JsFiddle 上吗? - Andrew Myers
1
我同意@Bill和@AndrewMyers的观点。最近在Khan Academy上进行了大量原型制作时,我发现使用image()方法时存在很重的GC开销。不确定这是由于Processing.js库还是Khan Academy沙盒的影响,但是回归到纯JavaScript可以消除小型100x100像素putImage()操作上约60MB/s的GC,并提供2-3倍的性能提升。看到处理相关图像的代码部分会有所帮助。 - Nolo
2
你应该将代码编辑的相关部分(以及额外的研究,如开发工具截屏)从你的 CodePen 示例中编辑到你的问题中,这样它就仍然有用,适用于未来遇到类似问题的人们,而不必依赖外部代码来源。 - doldt
显示剩余8条评论
3个回答

1
鉴于保持 Webkit 认为图像仍在显示可以消除问题(如您的不透明度实验所示),我会将其几乎完全移出可见区域,仅使用一个透明行与视口重叠(使用溢出隐藏)。
请注意,未打包的 4000x4000 精灵表将使用 64 兆字节的 RAM(每个像素4个字节(RGBA)),因此也许最好确保下一张图片提前“热身”一下,而不是一直保持所有图片都未打包?

1
虽然我已经尝试过类似的东西,但我会再试一次,并告诉你它是否有效。谢谢你的建议 :) 但是,与其使用这种hack方法,我最好改用Electron而不是NW。假设Electron能够正常工作。我不会切换到Electron并让这个问题未解决! :D - Darko Riđić

1
尝试直接切换到谷歌浏览器,因为新的NW版本可能已于2016年4月19日发布。之后,NW将希望跟上每个Chromium发布版本的步伐。在Chrome中不应该有相同的问题。

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

我只使用canvas元素进行预加载。但是我将支持canvas,并且“HTML”方式将作为备选方案。感谢您的建议 :) - Darko Riđić

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接