android工程师学习微信小程序笔记⑪ 小程序底层框架

双线程模型

管控与安全

要彻底解决这个问题,我们必须提供一个沙箱环境来运行开发者的JavaScript 代码。这个沙箱环境不能有任何浏览器相关接口,只提供纯JavaScript 的解释执行环境,那么像HTML5中的ServiceWorker、WebWorker
特性就符合这样的条件,这两者都是启用另一线程来执行 JavaScript。但是考虑到小程序是一个多 WebView 的架构,每一个小程序页面都是不同的WebView 渲染后显示的,在这个架构下我们不好去用某个WebView中的ServiceWorker去管理所有的小程序页面。

得益于客户端系统有JavaScript 的解释引擎(在iOS下是用内置的 JavaScriptCore框架,在安卓则是用腾讯x5内核提供的JsCore环境),我们可以创建一个单独的线程去执行 JavaScript,在这个环境下执行的都是有关小程序业务逻辑的代码,也就是我们前面一直提到的逻辑层。而界面渲染相关的任务全都在WebView线程里执行,通过逻辑层代码去控制渲染哪些界面,那么这一层当然就是所谓的渲染层。这就是小程序双线程模型的由来。

天生的延时

既然小程序是基于双线程模型,那就意味着任何数据传递都是线程间的通信,也就是都会有一定的延时。

这不像传统Web那样,当界面需要更新时,通过调用更新接口UI就会同步地渲染出来。

在小程序架构里,这一切都会变成异步。

异步会使得各部分的运行时序变得复杂一些。

比如在渲染首屏的时候,逻辑层与渲染层会同时开始初始化工作,但是渲染层需要有逻辑层的数据才能把界面渲染出来,如果渲染层初始化工作较快完成,就要等逻辑层的指令才能进行下一步工作。

因此逻辑层与渲染层需要有一定的机制保证时序正确,这些工作在小程序框架里会处理好,开发者只需要理解生命周期,以及控制合适的时机更新UI即可。

除了逻辑层与渲染层之间的通信有延时,各层与客户端原生交互同样是有延时的。以逻辑层为例,开发者的代码是跑在逻辑层这个线程之上,而客户端原生是跑在微信主线程(安卓上是线程)之上,所以注册给逻辑层有关客户端能力的接口,实际上也是跟微信主线程之间的通信,同样意味着有延时。这也是我们看到大部分提供的接口都是异步的原因。

组件系统

小程序里面设计了一套 组件框架 —— Exparser。

Exparser框架

Exparser是微信小程序的组件组织框架,内置在小程序基础库中,为小程序的各种组件提供基础的支持。小程序内的所有组件,包括内置组件和自定义组件,都由Exparser组织管理。

Exparser的组件模型与WebComponents标准中的ShadowDOM高度相似。

Exparser会维护整个页面的节点树相关信息,包括节点的属性、事件绑定等,相当于一个简化版的Shadow DOM实现。Exparser的主要特点包括以下几点:

  • 基于Shadow DOM模型:模型上与WebComponents的ShadowDOM高度相似,但不依赖浏览器的原生支持,也没有其他依赖库;实现时,还针对性地增加了其他API以支持小程序组件编程。
  • 可在纯JS环境中运行:这意味着逻辑层也具有一定的组件树组织能力。
  • 高效轻量:性能表现好,在组件实例极多的环境下表现尤其优异,同时代码尺寸也较小。

小程序中,所有节点树相关的操作都依赖于Exparser,包括WXML到页面最终节点树的构建、createSelectorQuery调用和自定义组件特性等。

组件的节点树称为“ShadowTree”,即组件内部的实现;最终拼接成的页面节点树被称为“Composed Tree”,即将页面所有组件节点树合成之后的树。在进行了这样的组件分离之后,整个页面节点树实质上被拆分成了若干个ShadowTree(页面的body实质上也是一个组件,因而也是一个ShadowTree)。

运行原理

在使用自定义组件的小程序页面中,Exparser将接管所有的自定义组件注册与实例化。

从外部接口上看,小程序基础库提供有Page和Component两个构造器。

以Component为例,在小程序启动时,构造器会将开发者设置的properties、data、methods等定义段,写入Exparser的组件注册表中。这个组件在被其它组件引用时,就可以根据这些注册信息来创建自定义组件的实例。Page构造器的大体运行流程与之相仿,只是参数形式不一样。这样每个页面就有一个与之对应的组件,称为“页面根组件”。(这个过程跟Java类和对象的概念非常相像)

在初始化页面时,Exparser会创建出页面根组件的一个实例,用到的其他组件也会响应创建组件实例(这是一个递归的过程)。组件创建的过程大致有以下几个要点:

  1. 根据组件注册信息,从组件原型上创建出组件节点的JS对象,即组件的this
  2. 将组件注册信息中的data 复制一份,作为组件数据,即this.data
  3. 将这份数据结合组件WXML,据此创建出Shadow Tree,由于Shadow Tree中可能引用有其他组件,因而这会递归触发其他组件创建过程;
  4. 将ShadowTree拼接到Composed Tree上,并生成一些缓存数据用于优化组件更新性能;
  5. 触发组件的created生命周期函数;
  6. 如果不是页面根组件,需要根据组件节点上的属性定义,来设置组件的属性值;
  7. 当组件实例被展示在页面上时,触发组件的attached 生命周期函数,如果Shadw Tree中有其他组件,也逐个触发它们的生命周期函数。
原创文章 152 获赞 1013 访问量 40万+

猜你喜欢

转载自blog.csdn.net/dpjcn1990/article/details/105763487