小程序双线程架构¶
双线程模型¶
分层介绍¶
- 小程序的逻辑层与渲染层分离,分别运行在不同的线程上。
- 他们之间通过系统层的 JsBridge 进行通信:逻辑层把数据变化通知到视图层,触发视图层页面更新;视图层把触发的事件通知到逻辑层进行业务处理。
渲染层(WebView)¶
- 一个小程序存在多个界面,所以视图层存在多个WebView线程
- 在 WebView 里处理 wxss/wxml
逻辑层(js Core)¶
- 在 js Core 里处理 javascript
为什么要双线程模型?¶
web 技术存在问题¶
- 体验:GUI 渲染线程与 js 逻辑线程互斥,导致一些逻辑任务抢占UI渲染的资源;这样会很慢。
- 管控:web页面自由度很高,需要花很大的人力去检查页面是否存在违规等操作。
选择混合(Hybrid)技术¶
- 界面由成熟的Web技术渲染,辅之以大量接口提供原生能力。
- 每个小程序页面使用不用的 webview 去渲染,提供友好交互体验,更接近原生,避免单 webview 的任务过于繁重。
解决管控与安全问题¶
- 为了阻止开发者使用浏览器提供的,如页面跳转、操作DOM、动态脚本等开放性问题;避免进入微信平台与开发者的攻防战
- 为了彻底解决安全性问题,必须提供一个沙箱环境来运行开发者 js 代码。
- 架构师视角:平台最核心的一个考量点是为案例提供足够能力的前提下,保证案例的逻辑不会危机平台的安全。
双层实现原理¶
双线程通信原理¶
- 数据驱动理念
- 逻辑层通过 Page 实例的
setData
方法传递数据到渲染层 - Native 中转:逻辑层与渲染层以 Native 作为数据传输通道
渲染层¶
- 数据驱动理念实践
- WXML 结构等价与一颗 DOM 树,通过一个 JS 对象(vnode)来表达 DOM 树结构。
- 在渲染层,宿主环境把 WXML 转换为 JS 对象,在逻辑层发生变更时,需要通过宿主环境提供的 setData 方法把数据从逻辑层传递到渲染层,把差异 apply 到原来的 DOM 树上,渲染出正确的UI 界面。
逻辑层¶
继续追问¶
为什么小程序不使用浏览器的线程模型?¶
- 小程序的宿主是微信,但版本迭代是独立的
- 小程序的定位是小而美,能力比Web差,具备微信提供的原生能力
-
小程序可以类比为:CodePen、JSFiddle
- CodePen 保证案例的 js 代码是 线程安全的
- CodePen 需要禁止操作 CodePen 网站的DOM
- CodePen 基于iframe 呈现程序效果,但不会把 js 代码完全拷贝到 iframe,而是经过一次编译流程后被注入到 iframe;基于安全考虑,编译过程中剔除一些危险代码
线程安全的其他思路?¶
- Web Worker:具有线程安全特性,worker 内js不能获取 window、DOM 对象
- Shadow DOM:是Web Components 规范的一部分,将 ShadowRoot 的模式设置为 closed,就可以禁止获取到 ShadowRoot 节点及内部DOM
- 问题:web worker 通信性能比较差