Taro 适配鸿蒙的框架原理和性能优化
如果无法正常显示,请先停止浏览器的去广告插件。
1. Taro 适配鸿蒙的框架原理和性能优化
京东零售 / 宣泽彬
2.
3. Taro 是什么
Taro 是一个开放式跨端跨框架解决方案
4. Taro 解决的问题
业务响应不及时 研发成本增加 代码维护困难
多框架支持 性能优化 插件化
5. Taro 解决的问题
…
6. Taro 解决的问题
…
支持更多的开发范式 & UI 框架
7. Taro 解决的问题
…
支持更多的前端生态工具链 & 上层框架
8. 目录
•
•
•
•
•
•
背景介绍
鸿蒙适配思路
鸿蒙适配原理
性能优化
成果展示
总结
9. 背景介绍
10. 为什么要适配鸿蒙
11. 为什么要适配鸿蒙
• 头部互联网厂商纷纷进场
• 鸿蒙 NEXT 不再支持 apk 安装包
• 鸿蒙方向岗位的增加
入门学习并适配鸿蒙 APP 应用逐渐成为一种趋势
12. 代价
需要学习新的语言和 API 从零入门门槛高
原有的项目需要进行重新开发 旧项目迁移至新平台成本大
13. 使用 Taro 的优势
1. 旧项目的快速迁移
2. Web 范式的新项目开发
3. 原有 Web 生态工具的复用
14. 鸿蒙适配思路
15. ArkTS & ArkUI
16. 鸿蒙 ArkTS 和小程序的相似之处
1. 都支持 JavaScript/TypeScript 的语法
2. 都可以用 template(小程序) 或者 component(ArkTS) 去表达和渲染复杂的 UI 结构
结论:和小程序类似的,在鸿蒙系统上模拟浏览器环境,跑通 Web 端代码,渲染 ArkUI 页面内容
17. 鸿蒙适配原理
18. 适配原理
• 节点渲染
• 样式解析
• 工程化串联
19. 节点渲染——设计思路
......
Mock
BOM
DOM
Element
Node
...
window
ArkUI
document
...
20. 节点渲染——模拟 DOM API
21. 节点渲染——模拟 BOM API
window
document
navigator
…
@rollup/plugin-inject
注入
Bundle
history
22. 节点渲染——自定义前端框架渲染器
23. 节点渲染——DOM 树递归渲染 ArkUI 组件
24. 节点渲染——ArkUI 组件绑定样式和事件
1. 绑定事件
2. 绑定样式
25. 节点渲染——整体流程
Vite 编译系统
ArkUI 渲染层
前端框架层
React/Vue
Taro 虚拟 DOM
1. 调用
4. 渲染
Taro 运行时
BOM
ETS Page
2. 渲染
ArkUIComponent
3. 传递 DOM 树
DOM
API
ArkUIComponent
DOM 树
ArkUIComponent
DOM 树的数据结构
ArkUIComponent
ArkUIComponent
26. 样式解析——为什么要做样式解析
鸿蒙应用
声明式属性设置
不一致
Taro 项目
W3C 规范
27. 样式解析
解析原理
•
•
•
•
CSS 样式
伪元素
嵌套样式
fixed 布局
28. 样式解析——CSS 样式
CSS 代码块
鸿蒙样式对象
29. 样式解析——CSS 样式
鸿蒙样式对象
JSX 节点
样式合并和应用
Reconciler
作为参数传入
运行时样式合并函数
渲染 ArkUIComponent
30. 样式解析——伪元素选择器实现
鸿蒙样式对象
携有伪元素选择器的 CSS 代码块
31. 样式解析——伪元素选择器实现
鸿蒙样式对象
JSX 节点
Reconciler
样式合并和应用
存在伪元素
伪元素
styleSheets
作为参数传入
运行时样式合并函数
伪元素样式对象作为样式属性一起合入
渲染 ArkUIComponent
渲染伪元素对应的
ArkUIComponent
32. 样式解析——样式嵌套解析
存在嵌套样式的 CSS 代码块
鸿蒙样式对象
33. 样式解析——样式嵌套解析
combine 函数
JSX 节点
JSX 节点
34. 样式解析——样式嵌套解析
combine 函数
以冒泡的形式
1. 收集子元素
2. 收集所有子孙元素
35. 样式解析——样式嵌套解析
A
A
B
生成关系表
C
D
E
C
B
D
E
子代: B C
所有子孙: B C
子代: D E
所有子孙: D E
子代:
所有子孙:
D
E
36. 样式解析——样式嵌套解析
A
样式选择器: .A .E
C
B
D
E
子代: B C
所有子孙: B C
子代: D E
所有子孙: D E
子代:
所有子孙:
D
E
37. 样式解析——样式嵌套解析
A
样式选择器: .A > .C
C
B
D
E
子代: B C
所有子孙: B C
子代: D E
所有子孙: D E
子代:
所有子孙:
D
E
38. 样式解析——样式嵌套解析
A
样式选择器: .A .C > .E
C
B
D
E
子代: B C
所有子孙: B C
子代: D E
所有子孙: D E
子代:
所有子孙:
D
E
39. 样式解析——样式嵌套解析
鸿蒙样式对象
combine 函数
JSX 节点
Reconciler
样式合并和应用
是否存在伪元素
伪元素
styleSheets
作为参数传入
运行时样式合并函数
伪元素对象作为样式属性一起合入
渲染 ArkUIComponent
渲染伪元素对应的
ArkUIComponent
40. 样式解析——与 Web 端的对比
节点树
样式树
合并
问题:
1. 实现难度较大
2. 节点数多时性能消耗大
3. 节点样式更新时需要人为 diff
找出变更节点
全局范围 文件范围
匹配 注入
节点
样式
样式
节点
41. 样式解析——fixed 布局
原页面节点层 layer = 0
fixed 层 layer = 1
JSX 节点
A
Reconciler
若
B
po
sit
ion
为
f ix
ed
C
42. 工程化串联全流程
AppEntry
PageEntry
@tarojs/runtim
e
@tarojs/vite-runner
DOM
用户代码
BOM
@tarojs/plugin-platform-harmony-
ets
...
TaroArkUIComponent
TaroArkTSAPI
43. 性能优化
44. 性能测试的方法
DevEco Studio Profiler
45. 主要性能瓶颈
• 一次性渲染的节点数过多
• ArkUIComponent 的初始化时间太长
• ArkUI 组件声明式属性绑多过多
• ArkTS 的执行效率较慢
主要性能瓶颈!
46. 主要性能瓶颈——渲染节点数过多
47. 主要性能瓶颈——渲染节点数过多
统一处理相对定位等布局情况
包裹 TaroComponentWrapper 组件
48. 主要性能瓶颈——渲染节点数过多
渲染一个自定义组件 渲染两个自定义组件
初始化一个自定义组件 初始化两个自定义组件
自定义组件渲染耗时翻倍!
49. 性能优化探索——合并自定义组件
50. 性能优化探索——半编译插件的方案选型
Babel
SWC
51. 性能优化探索——开发 Rust 半编译插件
识别静态 JSX 模版
判断节点是否可变
收集调用的组件和调用顺序
可变节点
添加 @State 装饰器
(提供双向绑定的更新功能)
生成半编译自定义组件
解决节点数过多的问题
52. 性能优化探索——@ObjectLink 和 @Observed 的副作用
造成性能损耗
53. 性能优化探索——使用 LazyForEach
注
册
t
lis
e
r
e
n
54. 性能优化探索——使用 LazyForEach
直接变更 childNodes 等数据
触发 listener 监听回调
通知对应的 LazyForEachItem 更新节点数据
55. 主要性能瓶颈——声明式属性绑定过多
56. 主要性能瓶颈——声明式属性绑定过多
缺点
• 会绑定很多不需要的属性
• 样式的绑定无法复用
性能较差
不利于代码变更和重构
57. 性能优化探索——使用动态属性绑定
1. 创建 Modifier 类,在类中声明需要动态绑定的属性
2. 构建 Modifier 实例
3. 绑定 Modifier 实例到对应的元素
58. 性能优化探索——使用动态属性绑定
0. 获取 Taro DOM 节点的样式对象
1. 创建 Modifier 类,在类中声明需要动态绑定的属性
2. 构建 Modifier 实例
3. 绑定 Modifier 实例到对应的元素
59. 成果展示
60. 成果展示——渲染一致性
61. 成果展示——UI 渲染性能不断趋近原生
渲染性能对比图
渲染耗时(ms)
1000 个节点
500 个节点
355
50 个节点
135
鸿蒙原生应用
53
633
Taro 转鸿蒙应用(优化后)
377
207
1,184
Taro 转鸿蒙应用(优化前)
631
147
0
300
600
900
1200
1500
62. 总结与展望
63. 总结——适配原理
Vite 编译系统
1. 样式解析
ArkUI 渲染层
前端框架层
用户代码
Taro 虚拟 DOM
2. 调用
5. 渲染
Taro 运行时
BOM
ETS Page
3. 渲染
ArkUIComponent
4. 传递 DOM 树
DOM
API
ArkUIComponent
DOM 树
ArkUIComponent
DOM 树的数据结构
ArkUIComponent
ArkUIComponent
64. 总结——性能优化的措施
动态属性绑定
• 声明式属性绑多过多
• 一次性渲染的节点数过多
• ArkComponent 的初始化时间太长
• ArkTS 的执行效率较慢
}
Rust 半编译方案接入
接入 LazyForEach 机制
65. 展望
性能上 功能上
• 类 React 框架的替换 • 支持 Vue2/Vue3/SolidJS
• CAPI 的接入 • 补全动态化能力
• 动态事件的绑定 • 提供高阶组件
• 提供更完善的混写方案
66. 欢迎开源社区一起参与鸿蒙的共建
67.
68.