微信小程序双线程架构

643 阅读4分钟

20220813161827

为了安全和管控, 小程序使用双线程执行: 视图线程和逻辑线程。

逻辑线程用来运行js代码, 主要由js引擎构成; 视图线程主要用来渲染视图, 主要由webview构成。下面的这张架构图更好的说明了这一点。

20220813172153

不同环境中,视图层和逻辑层的具体实现如下所示:

20220813165129

逻辑层把数据变化(setData)通知到视图层, 触发视图层更新视图。 视图将用户事件传递给逻辑层,逻辑层做相应响应处理。 逻辑层和视图层的数据传输实际上都是通过底层的WeixinJSBridge通过原生webview.evaluateJavascript方法实现的。

webview.evaluateJavascript方法的作用是在webview中执行js代码,并拿到返回结果,如下所示:

20220813170331

比如在逻辑层setData(data), WeixinJSBridge通过webview.evaluateJavascript方法拿到data数据, 然后传递给视图层。(注意: 这里的webview和视图层webview没有关系,我的理解是, 它的作用只是用来运行需要传递的js代码)

所以WeixinJSBridge的作用有两个:

  • 视图层和逻辑层的通信
  • 逻辑层调用Native

逻辑层和视图层的交互

20220813171204

上图为逻辑线程生命状态图, 单它很好的展示了逻辑层和视图层的交互过程, 逻辑层负责提供数据, 视图将逻辑称提供的数据与视图模版相结合来渲染视图。

视图的编译

20220813171427

与视图层相关的编译器有两个:wccwcsc

  • wcc负责将WXML编译成javascript代码。
  • wcsc负责将WXSS编译成javascript代码。

这里将模版编译javascript代码, 我的理解是形成了模版函数, 该模版函数接受setData提供的数据作为参数, 生产虚拟dom, 如下所示:

function template(data) => 虚拟DOM

最后将虚拟dom交给WAWebView来做对比渲染视图。

一般视图组件和原生组件

微信小程序的组件分为一般视图组件和原生组件,一般视图组件指的是小程序提供的ui组件库中(Exparser)的组件,比如<view />, <button>等; 原生组件指的是并不在Exparser的渲染体系下,而是由客户端原生参与组件的渲染,比如地图等。

关于一般视图组件和原生组件的更多内容可以查看组件系统

小程序将一般视图组件放在下面,将解析后生成的原生组件放在一般视图组件的上面,如下图所示:

20220813174012

setData的问题

小程序页面有时会卡顿,可能是因为setData, 因为setData的数据需要中转,中转的效率低下,因为数据传输使用的webview.evaluate方法,这个函数的参数是文本,每次调用都需要进行原生类型到文本再到原生类型的转换。所以如果setData传输的数据比较大,那么时间就比较长,从而页面看着会有卡顿,如下图所示:

20220813180859

从用户触发事件开始到渲染完成,如果时间过长就会感觉到卡顿。

微信为什么要造一个 WXS?

WXS与js不同,有自己的语法,虽然它们很像。

20220813181710

WXS不运行在逻辑线程中,而是运行在视图线程中,它直接操作视图数据,避免了跨线程的通信开销。

因为小程序在跨线程的通信存在性能瓶颈,所以才打造了WXS视图脚本。

WXS的问题
  1. WXS运行环境与其他JS代码是隔离的。
  • 无法使用其他JS代码定义的函数。
  • 无法使用wx api。
  1. WXS函数不能作为视图模版中事件回掉句柄。

小程序中js的限制

  1. 不能操作DOM

因为逻辑层运行在 JSCore中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。

  1. 基于安全考虑,小程序中不支持动态执行 JS 代码,即:
  • 不支持使用 eval 执行 JS 代码
  • 不支持使用 new Function 创建函数
    • new Function('return this') 除外

详细信息请查看小程序运行时/JavaScript 支持情况

参考链接