本文为Cube 技术解读》系列第三篇文章,之前上线的《支付宝新一代动态化技术架构与选型综述》《Cube卡片技术栈解读》欢迎大家回顾。
小程序作为动态化或者跨端开发的一种技术栈,在业界成为事实标准。Cube 作为一种轻量级小程序技术栈,具有体积小、启动快、内存占用低等特点,也比较适合“即用即走”的小程序场景。以下将重点介绍 Cube 小程序技术栈与技术演进实践(若无特殊说明,所有的数据和图表都是针对小程序)。
Cube 渲染小程序
模块组成
小程序视角,Cube 渲染引擎主要由以下模块组成:
  • Components:主要是小程序规范里的组件;
  • Layout:支持 Inline,Block,Flex,Inline-Block,Inline-Flex 等多种布局方式,还包括文本分词,断行等计算;
  • Style:支持样式解析,样式匹配,样式继承,伪类和伪元素等多种选择器;
  • Rendering:管理渲染相关 Render Tree,图片资源请求调度等;
  • Animation:JS 和 CSS 动画实现;
  • JS Bridge:和 JS 引擎桥接;
  • JS Engine:目前支持 V8,JSC,QuickJS;其中 Android 下支持 V8,QuickJS;
  • Compositor:用于动画和图层的合成器(开发中)。
线程模型
Cube 小程序技术栈内部有这么几个线程:Bridge,Layout,Render,Paint,UI 等。
  • Bridge 线程:执行 JS;与 AppX 桥接的类 DOM 的 JSAPI;处理 JS 相关事件;
  • Layout 线程:布局计算;样式计算与匹配;维护 Layout Tree;
  • Render 线程:维护 Render Tree;绑定数据;分层;
  • Paint 线程:生成绘制命令;
  • UI 线程:平台事件分发;UI 布局。
小结
  • 并行布局,异步绘制:这里的并行是指 JS 执行,Layout 布局 以及  Render 三者完全并行处理。由于 Layout 和 Render,Paint 等不在一个线程,因此是异步绘制;
  • 多个线程协同工作,有点像 CPU 的 5 级流水线。
值得注意得是Web 渲染引擎有个特点就是和 Node 相关的 DOM 操作必须和 JS 在一个线程。这就导致解析 HTML,布局,样式计算,DOM,JS (包括垃圾回收)都在一个线程里。带来的后果就是只有解析完文档才能看到 UI 效果,这也是 Web 渲染小程序白屏时间较长的一个原因。
Cube小程序技术栈,将“DOM操作” 和 JS 执行解耦。因此 JS 的 GC 不会影响 UI 呈现。这种实现对于加快小程序启动非常有帮助。由于布局计算和 JS 执行也解开耦合,因此一般不会由于 JS 执行阻塞 UI 交互。
Cube 小程序技术栈的特点
  • 体积小,启动快:主 so 只有 2.8 MB(如果包括 Ariver,AppX,InsideSDK,整体小程序技术栈最小是 5.7MB)。另外可以享受到 OS 的红利(包括 UI 的初始化和缓存);
  • 高性能:接近于原生体验;
  • 内存占用小:小程序技术栈初始化后(包括 Inside SDK,Cube,AppX),大约只需要 7.5 MB;
  • 支持 Android,iOS 双端。
与 Web 引擎对比
下面仅仅针对小程序场景与 Web 引擎对比:
Web
Cube
DSL
AXML
CSS
部分支持
DOM
不支持(有部分替代的接口)
Component2
插件
不支持(规划中)
组件
部分支持
开发工具
发布打包
IDE/CLI
CLI
JS 调试
预览 DOM
编辑样式
特性
JS 上下文
每个业务一个 Worker
所有业务共享一个 Worker
布局
CSS 里各种布局
CSS 里常用布局
样式
CSS 全集
CSS 子集
JS 引擎
V8/JSC/JSI
V8/JSI/JSC/QuickJS
特点
性能上
启动较慢,内存占用较大
启动快,体积小,内存占用低
技术演进
让小程序业务低成本适配 Cube 渲染小程序,需要做三方面的工作:
  • 拥抱 Web 技术,补齐前端开发常用的能力:包括 CSS,小程序组件等;
  • 完善相关工具:包括开发,调试,Profile,发布,打包等;
  • 针对 Cube 的架构特点,深入优化,并拉开和 Web 渲染的差异。提供更好的用户体验。
新的流式布局(Flow Layout)
最初 Cube 小程序使用只支持 Flex 布局 Yoga 用于布局计算。后面升级成支持 Block,Flex,Inline-Block等多种布局方式的 Flow Layout。从而解决开发者只能使用 Flex 布局的困扰。目前两个布局引擎 Cube 内部都支持。其中 Flow Layout 主要用在小程序,Yoga 用在卡片。两者能力差异如下:
Yoga
Flow Layout
display: none
display: flex
display: inline
display: block
display: inline-block
display: inline-flex
display: -webkit-box
display: grid
可以扩展支持
支持 CSS 样式表
老版本的 Cube 只支持内联样式和简单的 CSS 选择器;然而小程序并没有约束 CSS,因此 Cube 扩充支持 CSS 样式表,样式继承,多种选择器等。从而使得 Web 渲染切换到 Cube 渲染,适配成本大大降低。甚至部分小程序可以做到在小程序 IDE 里基于 Web 渲染开发,然后打包成 Cube 渲染产物在真机上预览。前端同学无需进行过多的修改和适配。
新老 Cube 版本,选择器支持上的差异如下:
老版本 Cube[1]
新版本 Cube
内联样式
id 选择器
类选择器
元素选择器
样式继承
伪类、伪元素
属性选择器
选择器分组
分组选择器
组合器
@keyframes
@fontface
@media
可扩展支持
注:
  • [1] 老版本 Cube 是指:钱包 10.2.0 以前版本;
  • 新样式能力基本上对标 Web 引擎的样式能力;
  • 新样式能力支持像这种复杂选择器。
    div > div.jarttopspan.yellowa#t1 {}.pixel-ratio-2.web1px::before {}div:nth-child(2n+1) {}input[type="button"] {}#blue,div > div.jarttopspan.yellowa#t1 {}
支持自动分词,断行(Inline Text)
最初 Cube 用的是 Android 和 iOS 提供的文本计算和绘制能力。这种技术方案(以下称为平台层 Text)存在3个问题:
  1. 性能问题:特别是 Android 下,利用 Android 平台层的接口实现文本布局计算,导致在文本较多的情况下,布局耗时在渲染整体耗时里占比较高;
  2. 富文本特性:富文本以及许多文本特性支持较麻烦;
  3. 各平台上实现文本效果存在细节差异或者兼容性问题。
针对上述问题,在 Flow Layout 基础上增强支持 Inline Text 布局计算文本。基于 Inline Text 可以较轻松实现以下富文本,图文混排,分词,自动换行等。
1.富文本
2.自动换行和分词
Inline Text 实现前后的文本样式对比如下:
平台层 Text
Inline Text
width: fit-content
overflow-wrap: break-word 或 anywhere
word-wrap: break-word 或 anywhere
text-align: jusify
待支持
text-align-last
text-align-start
待支持
text-emphasis
待支持
text-decoration: overline
待支持
text-decoration-color
待支持
line-break
待支持
word-break
white-space
vertical-align
font-family
font-face
font-weight
float
clear
line-height
  • 假设原有 Cube 采用平台层接口实现的文本特性称为:平台层 Text
  • 表示实现细节上不完善或者不完全支持;
  • 在 Inline Text 基础上可以实现功能丰富的富文本组件;
  • 值得一提的是:该实现非常精巧,对于 Cube 包体积只增加了 170KB。具体细节后续文章详细探讨。
文本布局计算耗时对比(文本节点较多场景):
Yoga
平台层 Text
Flow Layout
平台层 Text
Flow Layout
Inline Text
布局耗时
单位(ms)
456
763
170
采用 QuickJS 替代 V8
V8 虽然是性能最高的 JS 引擎,但是存在内存占用大,初始化较慢等不足。在 IoT 或者低端设备上这些不足会被放大。因此在这些设备上,Cube 采用 QuickJS 取代 V8。一方面降低内存占用,另外一方面提升初始化性能。
Cube 内部目前适配了多个 JS 引擎,具体如下:
  • 在 Android 移动端上使用 V8 和 JSI
  • iOS 上使用 JSC
  • IoT 等低端设备上使用 QuickJS
另外我们在开源 QuickJS 基础上做了些优化工作。优化的结果大致如下(后续文章将详细介绍):
V8 Bench
开源 QuickJS
优化后 QuickJS
效果
DeltaBlue
627
731
+16.5%
Crypto
893
933
+4.5%
RayTrace
459
1194
+160%
EarleyBoyer
973
1906
+95.9%
RegExp
178
265
+48.9%
Splay
756
1783
+135.8%
NavierStokes
1644
1643
0%
分数(越高越好)
672
991
+47%
支持动画和多媒体组件
除了上述基础组件和能力之外,动画和多媒体也是部分小程序不可缺少的。因此我们扩展支持了 VideoCanvasLottieLive Player 等组件支持。并应用于 TV 大屏小程序、小游戏以及直播场景上。
在低端设备上,如何提高动画帧率并且降低内存占用也做了深度的优化。以下是 Video 和 Canvas 组件在小程序中的效果图:
Cavas 组件
Video 组件
支持多种模式的小程序产物
目前 Cube 支持多种模式的小程序产物:NativeCubeShared
  • Native 模式:对应的是旧的 Cube 渲染小程序模式,不支持 CSS 样式表,只能支持内联样式和有限的几种 CSS 选择器。性能最高,兼容性较低;
  • Cube 模式:在 Native 模式进化而来,支持 CSS 样式表和多种 CSS 选择器。性能良好,支持常用的 CSS 样式和特性(包括样式继承,多种 CSS 选择器);
  • Shared 模式:为了降低 Web 渲染的小程序迁移或者过渡到 Cube 渲染而开发。在同一个小程序产物里既支持 Web 渲染一部分页面又支持 Cube 渲染一部分页面。而且 Cube 渲染的页面支持样式表。这样在性能和兼容性平衡。小程序产物相对于 Web 渲染的小程序,产物体积增加不会超过 10%。
Native 模式
Cube 模式
Shared 模式
小程序产物体积
较小
稍大
小程序性能
稍低
小程序兼容性
一般
稍高
新样式
不支持
支持
支持
新布局
支持
支持
支持
:如果需要 Web 产物兜底,则 Native 模式Cube 模式的小程序产物,比 Shared 模式大。
当前工作
Cube 小程序在 TV 和 POS 机上和相关团队,一起打磨小程序技术栈(包括渲染引擎,JS 引擎,AppX,Ariver 容器)等。
在 TV 上面临的问题:
  • 内存少:有的设备只有 512MB 内存,长列表滚动容易卡;
  • 需要支持焦点切换;
  • CPU 主频较低:有的只有 1GHz。
短中期目标是用小程序技术栈替代 WeeX 单页。当前进展如下:
  • 小程序启动性能上超过 WeeX 单页(低端设备上优势更明显);
  • 内存占用上,小程序初始化后内存占用小于 10MB,典型小程序整体内存占用在 32MB 左右。
具体细节后续文章详细总结。
在 POS 机上面临的问题:
在 POS 机上跑点餐小程序,主要有面临以下问题:
  • 内存少:部分设备只有 512MB 内存,容易出现卡死和 OOM;
  • CPU 核心少:部分 CPU 只有双核(硬件性能大约是主流手机的 1/5);
  • 长列表滚动卡。
短中期目标是用小程序技术栈替代 Flutter 开发的 App。当前进展如下:
  • 小程序首屏启动性能提升了 30%+;
  • 小程序重点的交互场景的页面,比如:购物车,商品详情页等,都已接近 Flutter App;
  • 首页滚动帧率达到 50,用户已经难以感知和 Flutter 的差异(Flutter 帧率是 60);
  • 小程序内存占用下降了 30%(本地测试已无卡死和 OOM)。
该场景主要是文本节点较多的长列表。采用了非常多的优化方法,后续文章详细总结介绍。
总结
为了适配小程序,Cube 渲染引擎在布局计算、样式能力、组件支持,还有开发工具等在小伙伴一起努力下取得了较大的进展。同时在低端设备(比如:IoT 设备)或者性能敏感场景,Cube 小程序性能优化,降低内存占用也取得了不错的效果。而未来面对多种多样的 IoT 设备,还需要加速技术演进以支持更多的场景。欢迎大家一起来交流讨论。
关注我们,每周 3 篇移动干货&实践给你思考!
继续阅读
阅读原文