基于 Worker 图表设计
AI 摘要讨论如何利用 Worker、OffscreenCanvas 和线程通信优化图表渲染性能。
在现有图表代码中,图表与图表,图表与业务代码都在同一条线程中,任何一处拥有复杂计算,都会使页面暂时失去响应。
Worker 基础
线程状态:Worker 线程存在 initial、active、terminated 三个状态,但对其它上下文不可见。如果未调用 terminate 或 close,线程不会处于 terminated 状态,内存信息不会消失。
线程通信三种方式:
- 结构化克隆算法:针对简单数据类型,相当于 deepClone
- 可转移对象:针对复杂数据类型(ArrayBuffer、MessagePort、ImageBitmap、OffscreenCanvas),引用从父上下文中抹去
- SharedArrayBuffer:完全原子化操作,需要添加 cross 标头
OffscreenCanvas
OffscreenCanvas 和 Canvas 的区别是 OffscreenCanvas 可以在 Worker 中使用。
两种使用方式:
- Transfer 模式:在 Worker 线程创建 OffscreenCanvas 做后台渲染,把渲染好的缓冲区 Transfer 回主线程显示
- Commit 模式:在主线程 DOM 树上产生 OffscreenCanvas,再发送给 Worker 线程进行渲染
ImageData vs ImageBitmap
- ImageData:Uint8ClampedArray,存储像素点 RGBA 值,可基于像素操作
- ImageBitmap:只读,封闭一块 GPU 缓冲区,实现了 Transferable 接口
渲染流水线
渲染流水线涉及多个线程:主线程、合成线程、栅格线程、GPU线程。
合成动画直接由合成线程处理,不需要走完整渲染流水线。传统 Canvas 走的是非合成动画。
Commit 模式的优势
使用 Commit 模式,浏览器直接将 OffscreenCanvas 的当前绘制缓冲区发送给 Display Compositor,拥有更短的渲染路径。
业务场景落地
当前图表分三层:配置层、解析层、渲染层。配置层和解析层可以直接放在 worker 里面。渲染层中主要是 preact、zrender、以及一些手势。
通过 postMessage 将信息发送到 worker 中,在 worker 中构造只读的 document 和 window 属性。将原本对外暴露的方法改成异步方法。
如果这个架构能落地,仪表版上的图表应该可以提高几倍性能。