微信小程序底层实现原理

wa 的运行环境

根据微信官方的说明,wa的运行环境有3个平台:

  • IOS 的 webkit(苹果开源的浏览器内核)
  • Android 的 X5(QQ浏览器内核)
  • 开发时用的 nw.js(C++实现的web转桌面应用)

根据官方文档,这三大运行环境是有所区别的:

运行环境 逻辑层 渲染层
iOS JavaScriptCore WKWebView
安卓 V8 chromium定制内核
小程序开发者工具 NWJS Chrome WebView

技术选型

目前来说,页面渲染的方式主要有三种:

  • Web 渲染。
  • Native 原生渲染。
  • Web 与 Native 两者掺杂,也即我们常说的 Hybrid 渲染。

native APP、hybrid APP、web APP三者的区别

小程序最终的呈现形式,是 WebView + 原生组件 的 Hybrid 渲染方式。可以用一种近似 Web 的方式来开发,并且还可以实现在线更新代码。

因此拥有以下优势:

  • 开发门槛Web 门槛低,不过 Native 也有像 React Native 这样的框架支持
  • 体验Native 体验比 Web 不要好太多,Hybrid 在一定程度上比 Web 接近原生体验
  • 版本更新Web 支持在线更新,Native 则需要打包到微信一起审核发布
  • 管控和安全:Web 可跳转或是改变页面内容,存在一些不可控因素和安全风险
    • 可能面临一些性能问题:在 Web 技术中,UI 渲染跟 JavaScript 的脚本执行都在一个单线程中执行,这就容易导致一些逻辑任务抢占 UI 渲染的资源。
  • 具有生命周期Natvie 有生命周期,Web 仅仅能够根据事件做出不同的调整

wa 的双线程

wa双线程官方图

小程序的渲染层和逻辑层分别由 2 个线程管理

  • 渲染层的界面使用了 WebView 进行渲染
  • 逻辑层采用 JsCore 线程运行 JS 脚本

双线程模型

  • 逻辑层:创建一个单独的线程去执行 JavaScript,在这个环境下执行的都是有关小程序业务逻辑的代码
  • 渲染层:界面渲染相关的任务全都在 WebView 线程里执行,由逻辑层代码控制渲染哪些界面。一个小程序存在多个界面,所以渲染层存在多个 WebView 线程

双线程通信

把开发者的 JS 逻辑代码放到单独的线程去运行,但在 Webview 线程里,开发者就没法直接操作 DOM。那要怎么去实现动态更改界面呢?

前面我们知道,逻辑层和渲染层的通信会由 Native (微信客户端)做中转,逻辑层发送网络请求也经由 Native 转发。

这是不是意味着,我们可以把 DOM 的更新通过简单的数据通信来实现呢?

Virtual DOM 相信大家都已有了解,大概是这么个过程:用JS对象模拟DOM树 -> 比较两棵虚拟DOM树的差异 -> 把差异应用到真正的DOM树上。

双线程通信图

双线程通信过程:

  1. 在渲染层把 WXML 转化成对应的 JS 对象。
  2. 在逻辑层发生数据变更的时候,通过宿主环境提供的 setData 方法把数据从逻辑层传递到 Native,再转发到渲染层。
  3. 经过对比前后差异,把差异应用在原来的 DOM 树上,更新界面。

而上述的通信过程,基本上是通过微信小程序的基础库来完成的。

wa 的基础库

小程序的基础库是 JavaScript 编写的,它可以被注入到渲染层和逻辑层运行。

主要用于:

  • 在渲染层,提供各类组件来组建界面的元素
  • 在逻辑层,提供各类 API 来处理各种逻辑
  • 处理数据绑定、组件系统、事件系统、通信系统等一系列框架逻辑

由于小程序的渲染层和逻辑层是两个线程管理,两个线程各自注入了基础库。

小程序的基础库不会被打包在某个小程序的代码包里边,它会被提前内置在微信客户端。 这样可以:

  • 降低业务小程序的代码包大小
  • 可以单独修复基础库中的 Bug,无需修改到业务小程序的代码包

Exparser 框架

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

Exparser 基于 WebComponentsShadowDOM 模型,但是不依赖浏览器的原生支持,而且可在 纯 JS 环境中运行。

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

现在微信小程序也支持自定义组件了,用法和组件间通信类似于 Vue

在内置组件中,有一些组件并不完全在 Exparser 的渲染体系下,而是由客户端原生参与组件的渲染。比如说 Map 组件。它渲染的层级比在 WebView 层渲染的普通组件要高。

wa 与 h5 的区别

从技术的发展角度来看,微信小程序是从微信中的 webViewJS-SDK 进化到了今天的形态。那么,小程序和普通的h5页面到底有什么区别呢?

  • 运行环境:小程序基于浏览器内核重构的内置解析器,而 h5 的宿主环境是浏览器。所以小程序中没有 DOMBOM 的相关 APIjQuery和一些 NPM 包都不能在小程序中使用
  • 系统权限:小程序能获得更多的系统权限,如网络通信状态、数据缓存能力等;
  • 渲染机制:小程序的逻辑层和渲染层是分开的,而 h5 页面 UI 渲染跟 JavaScript 的脚本执行都在一个单线程中,互斥。所以 h5 页面中长时间的脚本运行可能会导致页面失去响应。

wa 的生命周期

img

参考文档

小程序的底层框架

微信小程序底层实现原理