技巧
Konva 的性能优化手段不少,但它们各自解决的是不同的瓶颈。用错方向,努力会白费。
优化清单
batchDraw方法- 图层管理
- 形状缓存
- 动画优化
- 形状重绘
- 如果你的形状只有位置变换(
x和y, 没有scale,rotation),设置transformsEnabled = 'position'。 - 如果你不需要在图层上添加事件, 设置
layer.hitGraphEnabled(false), 或者使用Konva.FastLayer。 参见 演示。 - 对于移动应用程序将视口设置为:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">。 - 如果您发现在视网膜屏幕的设备上的性能不佳, 设置
Konva.pixelRatio = 1.确保结果的质量能满足您的需求。 - 当拖动节点时,您可以在单独的一个图层上移动它, 拖动完成后将其移回到原来的图层。
- 优化描边的绘制。
- 如果形状同时设置了填充,描边和透明度,您可以设置
shape.perfectDrawEnabled(false)。详细信息参见 禁用 Perfect Drawing。 - 尽可能设置
shape.listening(false)。 更多信息参见 Listening false。 - 防止内存泄漏。
常见问题
该从哪里开始优化?
先测量,不要凭感觉。打开浏览器的 Performance 面板录一段, 看时间花在哪——是脚本执行、还是 Canvas 绘制、还是布局。
经验上 Konva 应用的瓶颈按出现频率排序是:节点数量过多 > 每帧重绘了不需要重绘的图层 > 单个节点的绘制成本(阴影、滤镜、复杂路径)。 多数人一上来就去优化第三项,而真正的问题往往在前两项。
缓存是不是总能提速?
不是。cache() 把节点渲染成位图,之后每帧只贴图——前提是这张图不用重做。
如果节点每帧都在变(位置、颜色、尺寸),缓存就要每帧重建, 那比直接绘制还慢,因为多了一次离屏渲染和一次贴图。
判断标准很简单:这个节点多久变一次?几秒才变一次,缓存;每帧都变,别缓存。 注意位移和整体缩放不算「变」——移动一个缓存节点不需要重建缓存。
节点数量多少算多?
没有绝对数字,取决于每个节点的复杂度和有多少在监听事件。
一个粗略的参考:几百个简单图形通常没问题;上千个就要开始考虑 关掉不必要的监听、把静态部分合并缓存;上万个则需要改变思路—— 比如把静态内容预渲染成一张图片,只保留交互部分作为真实节点。
与其他方案的取舍
三种主要手段各有其适用信号,不要混为一谈:
分层(图层管理)解决的是「重绘范围过大」。 信号是:画面上只有一小部分在动,却每帧重绘全部内容。把动静分开即可。
缓存(图形缓存)解决的是「单个节点画得太慢」。 信号是:节点数量不多,但每个都带阴影、滤镜或复杂路径。
减少节点解决的是「节点太多」。信号是:节点数以千计,且多数是静态装饰。 办法是合并成一个自定义图形,或者预渲染成图片。
还有一类是关掉不需要的功能:禁用事件监听、 关闭 Perfect Drawing、 描边绘制优化。这些成本低、风险小, 可以先做,但收益通常不如前三项显著。