小程序底层架构
与浏览器对比
以微信小程序为例,与浏览器中的对应关系:
- js 开发逻辑代码 -> js -> v8
- wxss (多了rpx单位)控制样式 -> css -> 浏览器渲染器
- wxml xml语言 控制渲染层展示 -> html -> 浏览器渲染器 -> dom
浏览器
- 单线程 存在阻塞
小程序
- 双线程架构
- js 逻辑层
- wxml、wxss 视图层
- JSBridge 通信(可以实现相机、扫码)
微信小程序初级架构
- 所有的逻辑代码会打成一份,一个小程序只有一个逻辑层,包含所有页面逻辑 js
- 视图层(渲染层)一个页面对应一个
Webview
,小程序中页面栈最多十层。- webview 用来渲染 wxml 和 wxss
- 在本地开发工具,直接用 iframe
- 在客户端,用真的 webview
- webview 用来渲染 wxml 和 wxss
小程序运行环境
运行环境 | 逻辑层 | 渲染层 |
---|---|---|
iOS | JavaScriptCore | WKWebView |
安卓 | V8 | chromium定制内核 |
小程序开发者工具 | NWJS | Chrome WebView |
nw:node(io/网络/资源处理/js)-webkit(html/css)
底层实现(基础库)
基础库:对底层运行时的封装,提供事件、数据变更、通信、基础函数
底层需要实现的功能:
- 视图层和逻辑层的编译
- 逻辑层和视图层之间的通信
查看基础库
微信开发工具 -> 执行 openVendor()
-> 打开基础库
可以看到两个可执行文件:
- wcc: Wechat WXML Complier wxml 编译器
- wcsc: Wechat WXSS Compiler wxss 编译器
和基础库 xxx.wxvpkg
。
基础库内容
基础库用 wxappUnpacker 反编译,得到:
- WAWebview.js 视图层引擎
Foundation
基础模块- 提供环境变量 env、isService、isWebview、eventEmit、jsbridge、ready监听 配置
WeixinJSBridge
消息通信机制NativeBuffer
转换数据格式Reporter
日志系统exparser
组件系统 Shadow DOM、WebComponent 规范、wx-element- 提供友好交互的组件 picker、slider、swiper 等
- 承接原生组件 video、canvas 等
- 事件系统
- 注册组件
window.exparser.registerElement()
__virtualDOM__
- WAService.js 逻辑层引擎
Foundation
基础模块- 提供环境变量 env、isService、isWebview、eventEmit、jsbridge、ready监听 配置
WeixinJSBridge
消息通信机制- 路由管理
- 生命周期管理
__subContextEngine
: App、Page、Component getApp__virtualDOM__
:提供querySelector
方法
编译器
编译 wxml
wcc(Wechat WXML Complier) wxml 编译器 -> js
初始化时:
- 编译生成 js,执行 js 生成构建虚拟 dom 的函数
- 数据传递给 构建虚拟 dom 的函数,生成 vdom 描述
- vdom 描述经过组件系统 exparser 的解析构建真实 dom
数据变更时:
- 执行上面 2、3 步
- dom diff 对比、渲染
wxml 经过 WAWebview 编译成 js,js + 虚拟 dom -> wxml描述文件,交给组件系统 exparser,去渲染更新
编译 wxss
wcsc(Wechat WXSS Compiler) wxss 编译器 -> js
- 处理单位 rpx,根据手机物理像素及分辨率来计算实际应该为多少
- 生成新的 style,插入
初始化流程
渲染层
控制台输入 document.getElementsByTag('webview')[0]
得到渲染层。
- 初始化
__webviewId__
(标识当前是哪个 webview )、__wxAppCode__
- wcc 生成渲染器方法的代码(wxml -> js)
- 加载执行 wcsc 打包出来的代码(js代码),生成 css
- 初始化页面配置
- $gwx -> generateFunc(渲染器,执行生成虚拟 Dom),需要数据
- 触发自定义事件,传递渲染器函数
var generateFunc = $gwx(decodeName) if(generateFunc) { var CE = window.CustomEvent document.dispatchEvent(new CE('generateFuncReady', { detail: { generateFunc: generateFunc } })) } else { ... }
- 基础库
WAWebview
中监听了generateFuncReady
事件,该事件中会触发WexinJSBridge
,通知逻辑层渲染层已加载完成,等待逻辑层传数据。逻辑层执行完之后执行generateFunc
回调,并拿到逻辑层传来的数据,生成虚拟 dom - 虚拟 dom 描述经过组件系统 exparser 的解析构建真实 dom
逻辑层
控制台输入 document
得到逻辑层。
- 初始化配置项(页面配置项、全局配置项)
- 加载逻辑层基础库(维护了 Page、App、Component、wx.getSetting、wx.scanCode 等)
- 维护一个逻辑层渲染器,加载逻辑代码(开发者写的代码)
- 构建
__wxAppCode__
,保存所有页面的配置和渲染器方法