likes
comments
collection
share

梳理微信小程序框架-重新认识小程序

作者站长头像
站长
· 阅读数 10

一、微信小程序的技术架构

在浏览器中,Javascript采用的是单线程模型,为了提升渲染效率和减少脚本错误的产生,浏览器GUI渲染进程和JS进程是互斥的。

  • JS线程拥有修改DOM的能力,在GUI线程渲染未生成render树时,修改DOM无疑会报错
  • GUI线程在渲染完成后,JS线程存在使GUI线程重新渲染的可能,使得渲染效率低下

这就导致一些逻辑抢占UI渲染的资源,这个问题可以通过Web Worker 解决。

小程序的宿主是微信,在这个环境下要独立迭代并保证安全独立沙箱、Native等特性等的话,需要在iframe运行,并引入额外的编译器和Web Worker保证线程安全,Worker 线程负责计算,将结果通过 postMessage 传递给主线程,主线程负责渲染。

梳理微信小程序框架-重新认识小程序

这样的话小程序的性能就大大降低,所以在微信小程序中,两者是分开的,在各个运行环境及渲染非原生组件的环境也是不同的:

运行环境逻辑层渲染层
iOS / MacJSCoreWKWebView
AndroidV8Chromium定制内核
小程序开发者工具NWJSChrome WebView
PC端(window)Chrome内核Chrome内核

这里可以看到小程序的运行环境分成 渲染层(View)和 逻辑层(App Service)

  • 渲染层:界面使用了WebView 进行渲染,小程序存在多个界面,所以渲染层存在多个WebView线程
  • 逻辑层:采用JsCore线程运行JS脚本

这就类似于JSSDK的Hybird技术,界面用Web渲染,原生提供接口开放客户端的原生能力。那么在小程序中这两个进程是怎么通信的呢?如下图所示,渲染层和逻辑层的通信是由微信客户端(Native)中转,逻辑层的网络请求也是由Native转发。

梳理微信小程序框架-重新认识小程序

二、逻辑层到底是什么?

微信文档: 小程序开发框架的逻辑层使用 JavaScript 引擎为小程序提供开发者 JavaScript 代码的运行环境以及微信小程序的特有功能。逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。开发者写的所有代码最终将会打包成一份 JavaScript 文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似 ServiceWorker,所以逻辑层也称之为 App Service。

总而言之逻辑层是一个只能够运行 JavaScript ,不提供 DOM/BOM 操作的沙箱环境。

为了保障安全性和解决卡顿,逻辑层主要是:

  • 缺少相关的 DOM API 和 BOM API,阻止开发者不安全的操作
  • web worker来做js运行
  • js bridge通知渲染层WebView更新UI

逻辑层的核心JSCore是什么呢?这里还需引申下WebKit

WebKit是一个开源的浏览器网页排版引擎,包含WebCore排版引擎和JSCore引擎。WebKit是Sfari、Chromium等浏览器的排版引擎

梳理微信小程序框架-重新认识小程序

其中WebCore是核心的渲染引擎,JavascriptCore是WebKit默认内嵌的JS引擎。Google Chrome的V8、ReactNative和iOS平台上的Javascript引擎大都是内嵌JSCore的。

JSCore的目的是JS解释器,给App提供了JS可以解释执行的运行环境与资源。让基于JSCore的Hybrid(Bridge)能够相互调用。如下图,小程序的JSCore相比于浏览器缺少了DOM/BOM,相比于Node缺少了Native的直接调用。

梳理微信小程序框架-重新认识小程序

三、逻辑和渲染层通信

在渲染层,宿主环境会把WXML转化成对应的JS对象,在逻辑层发生数据变更的时候,我们需要通过宿主环境提供的setData方法把数据从逻辑层传递到渲染层,再经过对比前后差异,把差异应用在原来的Dom树上,渲染出正确的UI界面

小程序的双线程模型不同于单线程,逻辑层和渲染层的数据交互需要通过JSBridge,二者是通过发布订阅来实现数据的双向绑定,这样在逻辑层调用setData来改变 Model 层的数据就能够实现视图数据的异步更新。

比如说如下的小程序页面

<view class="container">

  <view class="userinfo">

   <text class="user-nickname">{{userNickName}}</text>

  </view>

</view>

微信小程序通过wcc工具编译wxml为js,得到 Virtual DOM 结构

{

  "tag": "wx-page",

  "children": [

   {

     "tag": "wx-view",

     "attr": {

       "class": "container"

     },

     "children": [

       {

         "tag": "wx-view",

         "attr": {

           "class": "userinfo"

         },

         "children": [

           {

             "tag": "wx-text",

             "attr": {

               "class": "user-nickname"

             },

             "children": [

               ""

             ],

             "raw": {},

             "generics": {}

           }

         ],

         "raw": {},

         "generics": {}

       }

     ],

     "raw": {},

     "generics": {}

   }

  ]

}

再通过parser将tag转换为真实DOM


<div class="container">

  <div class="userinfo">

   <span class="user-nickname">{{文字内容}}</span>

  </div>

</div>

css也是通过wcsc编译wxss为js,进行相应的转换后,通过 style 标签插入到文档的 head 里面。

总结下:

  • 逻辑层调用 setData 方法
  • 逻辑层将待传输数据转换成字符串,并拼接到特定的 JS 脚本,通JSBridge过将数据传输到渲染层
  • 渲染层接收到后,WebView JS 线程会对脚本进行编译,把待更新数据放入渲染队列,等待 WebView 线程空闲时进行页面渲染
  • WebView 线程开始执行渲染时,待更新数据会合并到视图层保留的原始 data 数据,并将新数据套用在 WXML 片段中得到新的虚拟节点树。经过新虚拟节点树与当前节点树的 diff 对比,将差异部分更新到 UI 视图。同时将新的节点树替换旧节点树,用于下一次重渲染

四、生命周期

这里梳理App、组件和页面相应的生命周期流程:

梳理微信小程序框架-重新认识小程序

从下方微信官方的原图能够很好的理解小程序页面的生命周期

梳理微信小程序框架-重新认识小程序

五、小程序方案与 React Native 对比

微信小程序React Native
框架* 渲染层使用WebView渲染WXML+WXSS* 逻辑层使用JsCore执行js脚本* 逻辑层网络请求经由微信native转发* JS 层:该层提供了各种供开发者使用的组件以及一些工具库(事件分发等)。* C++层:主要处理 java/OC 与 JS 的通信(JSBridge)以及执行 JavaScript(JS 脚本引擎)。* Native 层(Object C/Java 层):主要包括 UI 渲染器、网络通信等工具库。根据不同操作系统有不同的实现。
UI渲染* 在渲染层,宿主环境会把WXML可以先转成JS对象,然后再渲染出真正的Dom * 在逻辑层发生数据变更的时候,需要通过宿主环境提供的setData方法把数据从逻辑层传递到渲染* 对比前后差异,把差异应用在原来的Dom树上,渲染出正确的UI界面基于react框架(虚拟dom)* 首先Js层通过jsx编写的Virtual Dom来构建Component* Native层将其转成真实DOM插入到原生 App 的页面中* 当有变更,通过diff算法生成差异对象* 最终由 Native层将差异对象应用到原生App的页面元素
通信视图层<->客户端(大部分原生组件涉及)* iOS 利用WKWebView 的提供 messageHandlers 特性* 安卓则是往 WebView 的 window 对象注入一个原生方法,最终会封装成 WeiXinJSBridge 这样一个兼容层逻辑层<->客户端* iOS平台可以往JavaScripCore框架注入一个全局的原生方法* 安卓方面则是跟渲染层一致的基于JSCore实现js与java/oc交互* 把JSX代码解析成javaScript代码* 读取JS文件,并利用利用JS脚本引擎执行* 返回一个数组,数组中会描述OC/Java对象,描述对象属性和所需要执行的方法,这样就能让这个对象设置属性,并且调用方法。

参考文章

小程序「同层渲染」那些事(keng)

小程序开发指南

跨平台实现基础(一)JsCore 原理和实践

小程序开发指南要点整理

小程序发展史与小程序的原理技术

微信小程序基础架构浅析

React-Native与小程序的底层框架比较