各小程序框架实现思路学习记录
发表时间:2021-1-5
发布人:葵宇科技
浏览次数:65
小程序
已知,网页是单线程工作的,即是渲染进程在工作时,假如 JavaScript 引擎
执行 JavaScript
代码时,渲染进程会将控制权交予 JavaScript 引擎
,不会两个进程同时在工作。因为,JavaScript 引擎
可能会操作DOM
,所以,为了排除冲突,确保渲染正确,网页是单线程工作的。
但是,小程序,是双线程工作的。它分为逻辑层
跟视图层
。他们通过线程通信,共同完成视图的完整呈现和交互。此外,小程序不提供操作视图层
的元素的方法,所以它无法像网页那样用 JavaScript
去操作 DOM
元素去实现更新。
引自:小程序的运行环境
各平台脚本执行环境以及用于渲染非原生组件的环境是各不相同的:
在 iOS 上,小程序逻辑层的 javascript 代码运行在 JavaScriptCore 中,视图层是由 WKWebView 来渲染的,环境有 iOS 12、iOS 13 等;
在 Android 上,小程序逻辑层的 javascript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Mobile Chrome 内核来渲染的;
在 开发工具上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium Webview 来渲染的。
视图层
的实现是 webView
,但这是一个定制 webView
,它不能运行 JavaScript
,且内容也不是 html
。
那么,小程序为什么要实现双线程工作呢?官方回答如下:
- 快速的加载
- 更强大的能力
- 原生的体验
- 易用且安全的微信数据开放
- 高效和简单的开发
但,这个见仁见智吧。
Mpvue
在小程序整出一套 wxml
wxss
wxs
的组合拳时,其实是在给开发者增加负担。那有没有一种方案,是用自己熟悉的框架的语法去写,但是产出却是小程序呢?办法总是有的,Mpvue
先行一步。其实 vue runtime
并不涉及 DOM 的修改,它就是一整套的 JavaScript
方法,可以愉快地运行在小程序的逻辑层
。所以 Mpvue
复制了一套 Vue
库出来改造一下去实现这个伟大的目标。
实现原理如下:
// 这是 Vue 的实现
// template -> AST -> render -> vnode -> patch -> DOM
// ^
// /
// /
// js ---------> new Vue()
// 这是 Mpvue
// template -> AST -> render -> vnode -> patch -/-> DOM
// ^ |
// / |
// / V
// js ---------> new Vue() ---> setData
// \ /
// \-> page() /
//
复制代码
在创建 Vue
示例的时候,调用 page
方法,经过 Vue
处理后并不patch
到DOM
去渲染,而是通过 setData
去更新小程序实例上的数据,从而更新小程序的视图(因为小程序分了逻辑层和视图层,所以小程序并没有提供操作小程序节点的 API 方法)。
引自:【2万字长文】深入浅出主流的几款小程序跨端框架原理
小程序平台还规定,要在小程序页面中调用
Page()
方法生成一个page
实例,Page()
方法是小程序官方提供的 API。(解答为什么需要调用 page 方法)
此外,Vue
模板转小程序模板,生命周期对齐,事件处理等暂且不说。大体的实现原理就这些。
总结:
类Vue的小程序框架实现原理关键点:
- 实例化时,调用
page
方法 - 更改
Vue
流程,使用setData
来替代DOM
操作 Vue
模板转小程序模板,生命周期对齐,事件处理等
Taro 1 & 2
React
比 Vue
难处理的点在于,React
开发是非模板化的,使用了 jsx
,导致它太灵活了,不好圈定范围去转化为小程序的模板(我们知道模板转化主要是靠AST
来完成的,有限的范围可以更好地处理)。
但 Taro
还是啃下了这块硬骨头,当然,不是那么容易和愉快。限制很多,开发只是类 React
。
Taro
通过穷举法将类 React 的组件和元素,通过AST转化为小程序的模板,加上不管是类Vue还是类React的小程序框架都要做的事情:生命周期对齐,事件处理等,就这样,啃下了这块硬骨头。
总结:
主要是靠 AST 穷举完成模板转化(核心),除了拥有了 React 开发时的爽度外,React 的其他优势无法利用。但无论如何也是值得鼓励和称赞。
Remax & Taro Next
如同 Mpvue
先行者,Remax
在 React 类小程序框架
也迈出了重要的一步。
Remax 的口号是,使用真正的、完整的 React 来开发小程序 。
它是怎么达成这个目标的呢?请看下面的流程分析:
// Remax 分析
// ----------------------------------------------------
// --------------| react reconciliation |--------------
// -------------------------|--------------------------
// -------------------------V--------------------------
// ---------------| vNode and Effect List |------------
// -------------------------|--------------------------
// -------------------------V--------------------------
// ----------------| Remax vNode (json) |--------------
// -------------------------|--------------------------
// -------------------------V--------------------------
// --------------| miniProgrom setData |---------------
// -------------------------|--------------------------
// -------------------------V--------------------------
// ----------------| miniProgrom data |----------------
// -------------------------|--------------------------
// -------------------------V--------------------------
// -------------------| base.wxml |--------------------
// -------------------------|--------------------------
// ---------------------( 递归遍历 )---------------------
// -------------------------|--------------------------
// -------------------------V--------------------------
// --------------------| 页面 / 组件 |-------------------
复制代码
Remax
可以分为两个部分,一个是 react runtime
,包含 react
的除 render
之外的核心内容;另一部分就是 Remax
实现的渲染器。
引自:Remax 实现原理
Remax 的运行时本质是一个通过
react-reconciler
实现的一个小程序端的渲染器。
直白点,**Remax的核心大约是 React reconciliation + Remax 渲染器 + base.wxml **。
解释一下这:
React reconciliation
负责更新节点和更新时机,产出是vnode
;Remax 渲染器
,将以上产出的vnode
从原本应该渲染为DOM
的操作改为生成/更新自身vnode
树(此vnode
跟react
的vnode
不同,是Remax
创建的vnode
),产出是Remax vnode
;- 调用
setData
方法,让小程序更新数据,从而将Remax vnode
传递到小程序中,然后小程序根据data
和base.wxml
递归渲染出页面来。
总结:
Remax
和 Taro Next
实现思路是一致的,真正地让 React 运行时
在小程序的逻辑层
跑起来了,从而拥有比较完整的React开发体验。
实现的基础条件是,小程序的 template 支持动态递归渲染。
实现核心在于,Remax 渲染器将 React 运行时产出的 vnode 转化为 Remax vnode,从而拥有一颗完整的节点树。然后数据 + template 动态递归渲染,渲染出页面来。
类 Vue 小程序框架和拥有完整体验的类 React 小程序框架的实现思路对比
从上文可以看到,类 Vue 小程序框架
的实现思路是 **Vue 运行时 + AST 转化小程序模板 **。
而拥有完整体验的类 React 小程序框架
实现的思路是 React 运行时 + 运行在内存中的由各个框架维护的 vnode 树(非 VDOM 的 vnode) + 静态模板。
看起来,类 Vue 小程序框架
的实现思路更胜一层,但其需要对Vue
框架进行一定的改造,所以会比较依赖 Vue
。
而拥有完整体验的类 React 小程序框架
,有 React
的完整开发体验(这也很重要),但无法利用 React
的调度,是递归地渲染(这和 React
以前无调度版本很相似)。且有一个必要的基础条件,就是微信小程序的 template
支持动态递归(这是 Remax 的地基)。