大文档首屏渲染方案的一些思考和尝试
最近在处理一些优化方面的东西,大文档渲染的优化方案。这里简单记录分享一下。
一、服务端渲染
优点:服务端性能比较好,对移动端手机作用明显
缺点:大文档渲染完可能体积比较大,网络传输占时间比之前多,sheet 还是得回到前端渲染,得维护一套 node 代码,增加成本
二、分片滑动加载渲染
优点:由于只渲染到首屏和预加载一到两屏的文档,速度炒鸡快,理论上不会有边界,可以渲染任意大小的文档
缺点:需要解决未加载完全复制全文的 bug,拉滚动条可能卡顿(参考 Sheet 插入 Doc 性能后续优化点文中说的拉动卡顿问题),CMD + F 无法全文搜索,需要自己开发全文搜索的功能。需要修改 Changeset 计算的一些逻辑。
三、多线程分片拼接渲染
方案:利用 webworker 多线程,主线程将文档分为几个块,分发给 worker,worker 将这些块输出为字符串,最后拼接输出
优点:可以将主线程让给 sheet 并行渲染,渲染速度应该会快,不存在二中缺点
缺点:理论上还是存在边界,超级大的文档,还是渲染时间会有天花板
我决定周末试一波
周日简单开发了一下方案三
将 580 行约 2w6 千字的文档,clientVars 分为三块,分发给三个 worker 计算成 html 字符串。
渲染的核心代码并没有加入插件模块,只简单输出字符串。
方案 render 字符串出来的时间为 ms
优化前: 380 ms
方案三处理之后: 1200ms…
尴尬的事情发生了,一顿操作猛于虎,一看战绩零杠五,竟然是负优化。。。。
难受之余,分析了一下 1200ms 时间的构成,发现从 main thread 到 worker 之间 postMessage 的时间是整个负优化的来源,多达 900ms 到 1000ms。
看了 worker 的资料:
https://developers.google.com…
用 Transferable Objects 能大大提高 postMessage 的性能。
再试了一波,能把整个时间提升到 780ms,仍然有 400ms 在的时间可以优化。为毛官方的 demo postMessage 如此之快,我自己试的这么慢呢?
原因是我的 worker 的 js 相当的复杂,体积很大,每个 worker 启动的时候都需要去编译这些 js,所以导致了这个负优化的产生。理论上我们可以将各个 plugin 拆分为只 render 和其他的业务逻辑,能大大减少 worker js 的包体积。如果在包体积不好缩减的情况下,也可以采用预先初始化 worker 的方式来减少这个时间。这个方法可以在 web 容器化的方案里面使用.
后续
在文档 1100 多行(约 4w 字)的时候,全文渲染的时间达到 520ms,而此时多线程渲染依然保持在 220ms 左右.
结论
对于超大的文档,多线程提升的结果是显著的,而小一些的文档 500 行左右,意义不大。对于 Doc 插 sheet 的渲染可能有一些作用,可以把主线程让给表格渲染。