微信小程序架构

2022/2/7 小程序

🌙 技术选型

一般来说,渲染界面的技术有三种

  1. 用纯客户端原生技术来渲染(IOS、Android)
  2. 用纯web技术渲染(RN)
  3. 用客户端原生技术和web技术结合的混合技术(简称Hybrid技术)来渲染(原生+H5)

小程序技术选型分析过程如下:

  • 开发门槛:web门槛低,Native也有像RN这样的框架支持
  • 体验:Native比Web要好太多,Hybird在一定程度上比Web接近原生体验
  • 版本更新:Web支持在线更新,Native则需要打包到微信一起审核发布
  • 管控安全:web可跳转或是改变页面内容,存在一些不可控因素和安全风险

由于小程序的宿主环境是微信,如果用纯客户端的原生技术来编写小程序,那么小程序代码更新每次都需要与微信的代码一起发版,此种方法不行。

因此需要向web一样可以把随时可更新的资源甩在云端,通过下载到本地,动态执行和即可渲染出界面。但如果用纯web来渲染小程序,在一些复杂的交互上会有些性能问题,因为在web中UI和js脚本是互斥的,在一个线程中执行,这就容易导致一些逻辑任务抢占UI资源。

最终采用二者结合起来的Hybrid技术来渲染小程序,用近似web的开发方式来开发,可以实现在线更新代码,同时引入客户端原生参与组件(原生组件)也有以下好处:

  • 扩展web能力,例如像输入框组件 input textarea有更好的控制键盘的能力
  • 体验更好,同时也减轻webView的渲染工作。例如地图组件map这类较复杂的组件,其渲染工作不占用webview线程,而交给更高效的客户端原生处理。
  • 绕过setData、数据通信和重渲染流程,使渲染性能更好
  • 用客户端原生渲染内置一些复杂组件、可以提供更好的性能

🌙 逻辑层

小程序开发框架的逻辑层使用 JavaScript 引擎为小程序提供开发者 JavaScript 代码的运行环境以及微信小程序的特有功能。

作用:逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。

开发者写的所有代码最终将会打包成一份 JavaScript 文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似 ServiceWorker (opens new window),所以逻辑层也称之为 App Service

在 JavaScript 的基础上,我们增加了一些功能,以方便小程序的开发:

  • 增加 AppPage 方法,进行程序注册和页面注册。
  • 增加 getAppgetCurrentPages 方法,分别用来获取 App 实例和当前页面栈。
  • 提供丰富的 API,如微信用户数据,扫一扫,支付等微信特有能力。
  • 提供模块化能力,每个页面有独立的作用域。 注意:小程序框架的逻辑层并非运行在浏览器中,因此 JavaScript 在 web 中一些能力都无法使用,如 window,document 等。

🌙 视图层

框架的视图层由 WXMLWXSS 编写,由组件来进行展示。

作用:将逻辑层的数据反映成视图,同时将视图层的事件发送给逻辑层。

  • WXML(WeiXin Markup language) 用于描述页面的结构。

  • WXS(WeiXin Script) 是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。

  • WXSS(WeiXin Style Sheet) 用于描述页面的样式。

  • 组件(Component)是视图的基本组成单元。

🌙 双线层通信

视图层与逻辑层分别为不同的线程且单独运行,那么在webview里,开发者就没有办法直接操作dom 那么如何实现动态更改界面呢?

逻辑层和视图层通信会由native做中转,逻辑层发送网络请求也经由native转发。也就是说,可以把dom的更新通过简单的数据通信来实现 采用Virtual DOM(虚拟dom):即用js对象模拟DOM树 --> 比较两棵虚拟dom树的差异 --> 把差异应用到真正的dom树上

视图层和逻辑层的数据传输,实际上通过两边提供的 evaluateJavascript 所实现。用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。

🌙 渲染机制

双线程的渲染,其实是结合了一系列机制(模版绑定、虚拟 DOM、线程通信),最后整合的一个执行步骤。 1.通过模版数据绑定和虚拟 DOM 机制,小程序提供了带有数据绑定语法的 DSL (领域专用语言)给到开发者,用来在渲染层描述界面的结构。

<view>{{ message }}</view>
<view wx:if="{{ true }}">hello</view>
<checkbox checked="{{ false }}"></checkbox>
1
2
3

2.小程序再逻辑层提供了设置页面数据的api(即,setData

this.setData({
  key: value
})
// setData函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的this.data的值(同步)。
1
2
3
4

3.逻辑层需要更改界面时,只要把修改后的 data 通过 setData 传到渲染层。 传输的数据,会转换为字符串形式传递,故应尽量避免传递大量数据。

4.渲染层会根据前面提到的渲染机制重新生成 Virtual Dom树,并更新到对应的 DOM 树上,引起界面变化。

模板数据绑定的过程

  • 1.解析语法生成AST
  • 2.根据AST结果生成DOM
  • 3.将数据绑定更新至模板

🌙 虚拟dom

虚拟 DOM 解决了常见的局部数据更新的问题,例如数组中值位置的调换、部分更新。 计算过程如下:

  • 用JS对象模拟DOM树。 一个真正的DOM元素非常庞大,拥有很多的属性值。而其中很多的属性对于计算过程来说是不需要的,所以我们的第一步就是简化 DOM 对象。我们用一个 JavaScript 对象结构表示 DOM 树的结构。

  • 比较两棵虚拟DOM树的差异。 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异。通常来说这样的差异需要记录,最后得到一组差异记录。

  • 把差异应用到真正的DOM树上。 对差异记录要应用到真正的 DOM 树上,例如节点的替换、移动、删除,文本内容的改变等。

小程序里,由于无法直接操作 DOM,主要也是通过数据传递的方式来进行相关的模版更新。模版绑定的机制、数据更新的机制,都可以参照上面的说明。