HTML5 Canvas 全部 Konva 性能优化技巧列表
不想把时间浪费在性能问题上?可以请求一份性能评估。
为什么这很重要
HTML5 canvas 在其功能范围内效率很高,Konva
内部也有许多旨在提供良好性能的功能。然而,当你的项目开始变得复杂,或者舞台上有大量形状时,性能必然会受到一定影响。
优化目标
这里的优化聚焦于两个基本原则:
-
尽可能少计算:所有计算都需要时间完成。每一次计算可能只消耗极短时间,但成千上万甚至数百万次的计算——无论是你的代码、Konva、JavaScript,还是底层的图层——累计起来,如果那个超流畅的动画或效果出现卡顿,就能被肉眼察觉。
-
尽可能少绘制:这是关键,因为所有绘制都有性能成本。成本可以分为两类——首先是绘制所需计算时间(上述提到的计算部分),其次是将绘制内容从内存移动到屏幕所需时间。某些情况下,还可能涉及中间的离屏合成或每像素处理。因此,原则是尽可能少绘制。
舞台(Stage)
-
优化舞台大小 — 遵循“尽可能少绘制”原则,避免创建过大的舞台,因为从内存传输大量字节至屏幕会产生性能负担。这里有一些针对超大舞台问题的技巧参考此处!
-
在移动设备上设置视口 — 缩放图像会带来重大性能打击,因此在移动端应用中,设置视口标签:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
,以避免 Konva 输出被不必要地缩放。 -
在视网膜设备上使用
Konva.pixelRatio = 1
— Konva 会自动调整像素比例以保证在各种设备上绘制锐利图像。但如果视网膜设备性能不佳,可以设置Konva.pixelRatio = 1
来减少 Konva 的缩放开销。此设置在某些情况下可能影响输出效果,请确保最终画质符合你的需求。
图层(Layers)
-
图层管理 — 在底层,每个 Konva 图层相当于一个独立的 HTML5 canvas 元素,这带来了实用的能力,比如只刷新变更的图层以避免重绘整个舞台所消耗的性能。但强力带来责任,每个图层都会增加额外的性能开销,因此应将图层数量保持在较低水平。
-
使用
layer.listening(false)
— Konva 会在所有绘制的形状上监听鼠标和触摸事件,但每个监听都会消耗性能。图层中形状数量多时,Konva 需要花费大量时间来检查哪些监听器可能被触发。如果图层上的形状都不需要响应事件,可以通过layer.listening(false)
关闭该层的事件监听,减轻负担。示例见演示。形状部分也有类似建议。 -
优化拖动性能 — 拖动形状时,相关图层需在每个拖动事件周期重绘,为避免此性能成本,可拖动时将形状移动至专用图层,拖动结束再将其移回原图层。示例见演示。
形状(Shapes)
-
形状缓存 — Konva 内部会创建形状的图像缓存,并在需要时直接绘制该缓存。绘制图像相较于从绘制指令重组形状来说开销更小,能显著提升复杂形状或组的性能。
-
保持形状整洁 — 舞台上的每个形状存在都会消耗性能。为优化性能,应隐藏或从图层中移除那些已不可见(opacity=0)或超出视野的对象。
-
使用
shape.listening(false)
— 同图层(见上文第 7 点),Konva 会监听形状事件,这存在性能成本。告知形状不监听事件可减少此开销,详见关闭监听。 -
关闭完美绘制 — 有时 HTML5 canvas 绘制结果可能不符合预期,详见示例关闭完美绘制。Konva 通过完美绘制功能做了额外工作以修正,但这带来性能成本。设置
shape.perfectDrawEnabled(false)
可避免此成本,且在形状有填充、描边和不透明度的情况下不会降低质量。 -
优化描边绘制 — 为了实现预期绘制效果,当形状同时拥有描边和阴影时,Konva 会做额外的内部绘制。通过关闭 Konva 为描边添加的阴影,可以避免这一性能开销。
动画(Animations)
- 优化动画 — 避免为无视觉变化的动画步骤执行不必要的重绘。
内存(Memory)
- 避免内存泄漏 — Konva 已尽可能处理各种内存泄漏情况,但在创建形状和补间动画时,以及管理它们销毁时,你仍需要注意避免泄漏。
下面有个示例演示了上述部分性能优化技巧:
- Vanilla
- React
- Vue