最近实习中参与了H5项目向小程序迁移的工作,在微信官方文档和一些帖子上学习了小程序运行机制和底层原理,以及与Web页面的区别,在此基础上又看了一些关于小程序同构方案的内容。以下是我个人的一些学习总结。本文内容参考
1
在小程序诞生前,微信团队开发的JS-SDK使web开发者可以通过暴露的API使用微信原生能力去完成一些事,如调用接口打开微信支付等。针对移动端设备网络状态不稳定导致的白屏问题,微信又推出增强版JS-SDK,也就是“微信 Web 资源离线存储”,但在复杂的页面上依然会出现白屏的问题,原因表现在页面切换的生硬和点击的迟滞感。这个时候需要一个JS-SDK处理不了的,使用户体验更好的一个系统,即小程序。
小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。
其本质是运行在webview上的H5应用,但与H5又有着本质上的不同。H5可以理解为运行在移动端的web页面,本质还是由HTML+CSS+JS构成的web应用。小程序和H5的区别也就是小程序和网页的区别。
2
小程序与普通网页开发是有很大差别的,这就要从它的技术架构底层去剖析了。还有比如习惯Vue,react开发的开发者会吐槽小程序新建页面的繁琐,page必须由多个文件组成、组件化支持不完善、每次更改 data 里的数据都得setData、没有像Vue方便的watch监听、不能操作Dom,对于复杂性场景不太好,之前不支持npm,不支持sass,less预编译处理语言。
小程序的主要开发语言是 JavaScript ,小程序的开发同普通的网页开发相比有很大的相似性。对于前端开发者而言,从网页开发迁移到小程序的开发成本并不高,但是二者还是有些许区别的。
处于性能和实现的考虑,小程序采用Hybrid渲染机制,这样做有几点好处:
如下图所示,原生小程序框架采用双线程模型:视图层和逻辑层完全分离为两个不同的线程。每个页面的渲染在一个webview线程上执行,视图层包含多个webview线程,而逻辑层则统一在JSCore上执行。
这样做的目的是防止逻辑层对Dom和window的操作(如跳转到外部页面),使整个应用变得安全可控。
双线程模型下,逻辑层代码无法直接操作Dom,逻辑层和视图层的数据传输(setData)是通过两边的evaluateJavaScript实现的。用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。
小程序的基础库
小程序的基础库可以被注入到视图层和逻辑层运行,主要用于以下几个方面:
由于小程序的渲染层和逻辑层是两个线程管理,两个线程各自注入了基础库。
小程序的基础库不会被打包在某个小程序的代码包里边,它会被提前内置在微信客户端。
这样可以:
4
运行机制
小程序启动会有两种情况,一种是「冷启动」,一种是「热启动」。假如用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需将后台状态的小程序切换到前台,这个过程就是热启动;冷启动指的是用户首次打开或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动。
小程序没有重启的概念
当小程序进入后台,客户端会维持一段时间的运行状态,超过一定时间后(目前是5分钟)会被微信主动销毁
当短时间内(5s)连续收到两次以上收到系统内存告警,会进行小程序的销毁
很多企业都有自己的小程序平台,如微信、支付宝、头条等,如今市面上很多产品都是基于React、Vue等框架开发的web应用,但web端代码是不可能运行在小程序平台上,而开发几套代码的时间和维护成本又太高,为了节省学习和开发成本,各大公司都推出了自己的多端小程序方案,使开发者可以用React、Vue框架来开发小程序。类似框架有微信的Kbone、阿里的Remax、京东的Taro等。
Taro是在编译时将代码适配到小程序平台,而Kbone和Remax则是在运行时完成这个工作。
5
以下重点解释Kbone和Remax。
参照微信官方文档,Kbone在适配层里模拟出了浏览器环境,让 Web 端的代码可以不做什么改动便可运行在小程序里。
因为 kbone 是通过提供适配器的方式来实现同构,所以它的优势很明显:
由于Kbone是通过牺牲部分性能来实现适配的,所以在性能要求极高的场景如多节点、多数据页面,还是建议用原生开发。
kbone实现原理是在worker线程适配了一套JS Dom API,上层不管是哪种前端框架(react、vue)或原生JS最终都需要调用JS Dom API操作 dom,适配的 JS Dom API则接管了所有的Dom操作,并在内存中维护了一棵Dom tree,所有上层最终调用的Dom操作都会更新到这棵Dom tree中,每次操作(有节流)后会把Dom tree同步到webview线程中,通过wxml自定义组件进行 render。
与Kbone上层支持多种框架(React、Vue、Angular)不同,Remax专门实现React应用向小程序的适配。
Remax实现原理是在worker线程维护一棵虚拟Dom tree,这棵虚拟Dom tree会通过小程序原生的setData方法映射到render线程,render层再把虚拟Dom tree进行遍历然后渲染。
Remax和kbone类似,都是在 worker 线程维护一棵Dom tree,再把这棵 Dom tree传到render线程进行渲染,唯一的区别是remax dom tree发生变化时,会计算差异,而不需要把整棵树都传到render线程,此功能是react提供的,就是在 diff 完后找出差异,则把差异传到render线程。
6