基于 Worker 图表设计

AI 摘要讨论如何利用 Worker、OffscreenCanvas 和线程通信优化图表渲染性能。

在现有图表代码中,图表与图表,图表与业务代码都在同一条线程中,任何一处拥有复杂计算,都会使页面暂时失去响应。

Worker 基础

线程状态:Worker 线程存在 initial、active、terminated 三个状态,但对其它上下文不可见。如果未调用 terminate 或 close,线程不会处于 terminated 状态,内存信息不会消失。

线程通信三种方式:

  1. 结构化克隆算法:针对简单数据类型,相当于 deepClone
  2. 可转移对象:针对复杂数据类型(ArrayBuffer、MessagePort、ImageBitmap、OffscreenCanvas),引用从父上下文中抹去
  3. 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 属性。将原本对外暴露的方法改成异步方法。

如果这个架构能落地,仪表版上的图表应该可以提高几倍性能。