为了安全和管控, 小程序使用双线程执行: 视图线程和逻辑线程。
逻辑线程用来运行js代码, 主要由js引擎构成; 视图线程主要用来渲染视图, 主要由webview构成。下面的这张架构图更好的说明了这一点。
不同环境中,视图层和逻辑层的具体实现如下所示:
逻辑层把数据变化(setData)通知到视图层, 触发视图层更新视图。
视图将用户事件传递给逻辑层,逻辑层做相应响应处理。
逻辑层和视图层的数据传输实际上都是通过底层的WeixinJSBridge
通过原生webview.evaluateJavascript
方法实现的。
webview.evaluateJavascript
方法的作用是在webview中执行js代码,并拿到返回结果,如下所示:
比如在逻辑层setData(data)
, WeixinJSBridge
通过webview.evaluateJavascript
方法拿到data
数据, 然后传递给视图层。(注意: 这里的webview和视图层webview没有关系,我的理解是, 它的作用只是用来运行需要传递的js代码)
所以WeixinJSBridge
的作用有两个:
- 视图层和逻辑层的通信
- 逻辑层调用Native
逻辑层和视图层的交互
上图为逻辑线程生命状态图, 单它很好的展示了逻辑层和视图层的交互过程, 逻辑层负责提供数据, 视图将逻辑称提供的数据与视图模版相结合来渲染视图。
视图的编译
与视图层相关的编译器有两个:wcc
和wcsc
。
wcc
负责将WXML
编译成javascript
代码。wcsc
负责将WXSS
编译成javascript
代码。
这里将模版编译javascript
代码, 我的理解是形成了模版函数, 该模版函数接受setData
提供的数据作为参数, 生产虚拟dom, 如下所示:
function template(data) => 虚拟DOM
最后将虚拟dom交给WAWebView
来做对比渲染视图。
一般视图组件和原生组件
微信小程序的组件分为一般视图组件和原生组件,一般视图组件指的是小程序提供的ui组件库中(Exparser)的组件,比如<view />
, <button>
等; 原生组件指的是并不在Exparser
的渲染体系下,而是由客户端原生参与组件的渲染,比如地图等。
关于一般视图组件和原生组件的更多内容可以查看组件系统。
小程序将一般视图组件放在下面,将解析后生成的原生组件放在一般视图组件的上面,如下图所示:
setData的问题
小程序页面有时会卡顿,可能是因为setData
, 因为setData
的数据需要中转,中转的效率低下,因为数据传输使用的webview.evaluate
方法,这个函数的参数是文本,每次调用都需要进行原生类型到文本再到原生类型的转换。所以如果setData
传输的数据比较大,那么时间就比较长,从而页面看着会有卡顿,如下图所示:
从用户触发事件开始到渲染完成,如果时间过长就会感觉到卡顿。
微信为什么要造一个 WXS?
WXS与js不同,有自己的语法,虽然它们很像。
WXS不运行在逻辑线程中,而是运行在视图线程中,它直接操作视图数据,避免了跨线程的通信开销。
因为小程序在跨线程的通信存在性能瓶颈,所以才打造了WXS视图脚本。
WXS的问题
- WXS运行环境与其他JS代码是隔离的。
- 无法使用其他JS代码定义的函数。
- 无法使用wx api。
- WXS函数不能作为视图模版中事件回掉句柄。
小程序中js的限制
- 不能操作DOM
因为逻辑层运行在 JSCore中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。
- 基于安全考虑,小程序中不支持动态执行 JS 代码,即:
- 不支持使用 eval 执行 JS 代码
- 不支持使用 new Function 创建函数
- new Function('return this') 除外
详细信息请查看小程序运行时/JavaScript 支持情况。