小程序的双线程设计
WebView + JsBridge
小程序分为渲染层(由WebView线程管理)和逻辑层(由客户端JavaScript解释引擎线程管理)
Web技术是非常开放灵活的,开发者可以利用JavaScript脚本随意地操作DOM,危害用户的网站的安全。
双线程设计:
- 可以防止恶意攻击者的XSS攻击
- 可以防止开发者恶意盗取用户敏感信息。
- 提升页面加载性能 痛点:
- 浏览器中的DOM、BOM等对象和API,都无法在小程序中使用
- 小程序的一些API使用方式与浏览器行为不一致(请求、资源等)
- 逻辑层和渲染层的通信依赖客户端进行通信,当通信过于频繁,可能会导致性能问题。
双线程的通信设计
在小程序中,不管是逻辑层还是渲染层,都是用 微信客户端Native 进行直接通信,同时用于与其他模块或者外部进行中转通信。
1.虚拟DOM设计
- 在渲染层里,把WXML转化成对应的用于描述
虚拟DOM树的JS对象 - 在逻辑层发生数据变更的时候,通过宿主环境提供的
setData方法,把变更从逻辑层传递到Native,再转发到渲染层。 - 在渲染层里。经过对比前后差异,
把差异应用在原来的Virtual DOM 树上,更新界面。
2.Shadow DOM模型(shadow Root、shadow Tree)
什么是 Shadow Tree
Web components 是一个重要属性是封装:可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。
Web Component中的三项技术
- Custom elements 自定义元素
- Shadow DOM 影子DOM
- HTML template HTML 模板
其中,shadow DOM 接口是关键所在,它可以将一个隐藏的、独立的DOM 附加到一个元素上。
渲染层渲染过程
初始渲染
渲染层在接收到初始数据(data)时,需要进行渲染层渲染。
- 初始渲染时,将初始数据套用在对应的 WXML 片段上生成节点树。
- 初始渲染中得到的 data 和当前节点树会保留下来用于重渲染。
减少 WXML 中节点的数量,可以有效降低初始渲染和重渲染的时间开销,提升渲染性能。
重渲染
渲染层在接受到更新数据时(setDate 数据)时,需要进行渲染层渲染。
虚拟DOM设计
- 每次重渲染时,将data和setData数据套用在WXML片段上,得到一个新节点树。
- 将新节点树与当前节点树进行比较,这样可以得到哪些节点的哪些属性可以更新、哪些节点需要添加或移动。
- 最后,将setData 数据合并到data中,并用新节点树替换旧节点树,用于下一次重渲染。
去掉不必要设置的数据,减少setData 的数据量也有助于提升这一个步骤的性能。
自定义组件的渲染?
Shadow-Tree
-
逻辑层新建组件,并通知渲染层
- 逻辑层:
- 首先WXML 和 JS 需要生成一个 JS 对象。
- 然后JS的结点部分生成 Virtual DOM 信息。
- 最后通过底层通信通知到渲染层。
- 渲染层
- 拿到 Virtual DOM 节点信息
- 创建 Shadow DOM ,拼接 Shadow Tree
- 注入初始数据渲染
- 逻辑层:
-
逻辑层调用 setData,更新数据到渲染层
逻辑层执行逻辑,调用setData之后,会在逻辑层进行 DOM diff,然后将Diff 结果传到渲染层。(注意此处与之前的渲染流程不一致)
-
渲染层组件更新
渲染层拿到 diff 信息,更新 Virtual DOM 信息,同时更新页面
原生组件的同层渲染
由于原生组件脱离在WebView 渲染流程外,导致原生组件层级最高
同层渲染:小程序通过某种hack方式将原生组件插入可控层级,使得原生组件的层级和非原生组件一样可控,从而解决了遮挡的问题。