当咱们前端切图崽网上冲浪的时候,会发掘有非常多技术文案都在分析vue框架,react框架,显少有分析小程序框架的。那今天就经过这篇短小精悍的文案带大众认识一下微X小程序的底层架构。(如无特殊说明,下文中说到的小程序都是微X小程序)
小程序的由来
咱们先抛出一个问题,在无小程序的时候,企业们都在微X里怎么运营? 答案便是小程序的“前身”-公众号,企业们广泛会把H5网站放在公众号做为流量转换的入口。然则h5确实让公众号遇到了有些问题。
首要便是白屏过程,针对有些繁杂页面,受限于设备性能和网络速度,白屏会更加显著;再便是缺少操作反馈,例如页面切换生硬以及点击所带来的迟滞感等等;
微X团队内部经过JS-SDK以及后来的加强JS-SDK已然能够处理有些问题,然则针对以上问题是JS-SDK所处理不了的,急需一个全新的系统来完成,它需要具备以下能力: 快速加载更强大的能力原生的体验易用且安全的微X数据开放有效,简单的研发
于是,小程序诞生了。
双线程架构
此处点题一下,本文咱们讨论的是小程序的底层架构,其实,双线程架构便是小程序的核心。那为何要设计成双线程架构呢?首要咱们来回顾一下浏览器的线程模型,浏览器是一个单线程架构,重点原由是js准许拜访操作DOM,因此呢js线程和渲染线程只能互斥运行。
那小程序又是怎样做到双线程的呢,基本原由便是微X小程序禁止js操作DOM。
运用双线程架构的优良一目了然: 加强用户体验(ui和规律分离,避免页面长期阻塞和卡顿)优化应用性能(运行在区别的线程中,能够同期渲染或计算)研发效率更高(解耦和松散耦合)接下来就带大众认识一下渲染层以及规律层的设计思路。
设计思路-渲染层
标签实现
小程序运用的是Exparser组件模型,Exparser组件模型与Web Components中的shadow DOM高度类似,微X为何运用自定义组件框架,而不运用Web Components呢?重点还是出于安全思虑,并且方便管控。既然Exparser组件框架与shadow DOM高度类似,那样咱们首要来认识一下shadow DOM。
shadow DOM: Web Components的一个重要属性是封装-能够将标记结构、样式和行径隐匿起来,并与页面上的其他代码相隔离,保准区别的部分不会混在一块,可使代码更加干净、整洁。其中,shadow DOM接口是关键所在,它能够将一个隐匿的,独立的DOM附加到一个元素上。
shadow DOM准许将隐匿的DOM树附加到常规的DOM树中-它以shadow root节点为初始根节点,在根节点的下方,能够是任意元素,和普通的DOM同样。
以上解释源自于MDN,其实shadow DOM并不奥秘,像咱们非常熟练的video标签本质上便是用shadow DOM实现的。咱们先打开chrome浏览器设置中的“打开用户代理shadow DOM”,而后再点击video标签就能看到。
创建shadow DOM亦非常简单,直接运用attachShadow办法就能够创建。 var shadow = Element.attachShadow({ mode: closed
})
Exparser组件模型:Exparser组件模型参考了shadow DOM并进行了有些修改,像事件系统就是完全复刻的,slot插槽,属性传递等都基本一致。但同期它又拥有有些特点: 基于shadow DOM模型:模型上与Web Components的shadow DOM高度类似,但不依赖浏览器的原生支持,亦无其他依赖库;实现时,还针对性地增多了其他API以支持小程序组件编程;可在纯JS环境中运行:这寓意着规律层亦拥有必定的组件树组织能力;有效轻量:性能表现好,在组件实例极多的环境下表现尤其优异,同期代码尺寸亦较小;WXML编译
认识了小程序的组件系统之后,接下来瞧瞧WXML的编译过程。小程序中的DOM编译流程与vue类似,亦会先将代码字符串编译为虚拟DOM,小程序中的虚拟DOM结构如下:WXML最后会被编译为JS文件,而后插进到渲染层的script标签中。
WXSS动态适配
WXSS是小程序中运用的样式语言,WXSS拥有CSS的大部分特性,同期它对CSS进行了扩充以及修改。
小程序中运用的尺寸单位为rpx(Responsive px),区别于h5中针对px的处理,需要运用postcss进行统一的转换,小程序底层已然为研发者做好了这层转换,那详细它是怎么做到的呢?
咱们看它的这段源码,其实它与阿里的flexible.js方法是类似的,区别的是它做了一个精度收拢的优化,重点是为认识决1px的问题。
WXSS一样会经过编译,最后的编译产物为wxss.js,区别于WXML经过script标签的形式插进到渲染层,wxss.js则是经过eval的方式注入到渲染层代码中。
渲染层webview
全局变量: 渲染线程中存在着以下全局变量。 webviewId:webview的独一标识,当用户打开一个小程序页面的时候,相当于打开了一个webview,区别的webview用webviewid来区分;wxAppCode:全部页面的json wxss wxml编译之后都存储在这儿;Vd_version_info:版本信息;./dev/wxconfig.js:小程序默认总配置项,包含用户自定义与系统默认的整合结果。在掌控台输入__wxConfig能够看出打印结果;./dev/devtoolsconfig.js:小程序研发者配置,包含navigationBarHeight,标题栏的高度,状态栏高度,等等,掌控台输入__devtoolsConfig能够看到其对应的信息;./dev/deviceinfo.js:设备信息,包括尺寸/像素点pixelRatio;./dev/jsdebug.js:debug工具;./dev/WAWebview.js:渲染层底层基本库;./dev/hls.js:优秀的视频流处理工具;./dev/WARemoteDebug.js:底层基本库调试工具;那小程序是怎样快速起步一个webview的呢?
咱们在打开pages/index/index视图页面时,发掘DOM中多加载了一个__pageframe__/pageframe.html的视图层。这个视图层的功效正是小程序提前为一个新的页面层准备的。小程序每一个视图层页面内容都是经过pageframe.html模板来生成的,包含小程序起步的首页。
下面来瞧瞧小程序为快速打开小程序页面做的技术优化: 首页起步时,即第1次经过pageframe.html生成内容后,后台服务会缓存pageframe.html模板首次生成的html内容;非首次新打开页面时,页面请求的pageframe.html内容直接走后台缓存;非首次新打开页面时,pageframe.html页面引入的外链js资源走本地缓存; 这般在后续新打开页面时,都会走缓存的pageframe的内容,避免重复生成,快速打开一个新页面。视图层打开新页面的流程
在创建每一个视图层页面的webview时,都会为其绑定了onLoadCommit事件(它会在页面加载完成后触发,包括当前文档的导航和副框架的文档加载)。初始时webview的src会被指定为空页面位置http://127.0.0.1{global.proxyPort}/aboutblank?${c},其中c为对应webview的id。webview从空页面到详细页面视图的过程如下: 空页面位置webview加载完毕后执行事件中的reload办法,即设置webview的src为pageframe位置;加载完成后,设置其src为pageframe.html, 新的src内容加载完成后再次触发onLoadCommit事件但按照要求不会执行reload办法;pageframe.html页面在dom ready之后触发注入并执行详细页面关联的代码,此时经过history.pushState办法修改webview的src然则webview并不会发送页面请求;设计思路-规律层
接下来咱们瞧瞧小程序在规律层都做了那些事情。
规律层与视图层通信
在小程序中,规律层仅有一个,然则渲染层有多个,渲染层和规律层之间是经过微X客户端进行桥接通信的。那详细是怎么实现的呢?其实它运用的便是WeixinJSBridge通信机制。
在小程序执行的过程中,微X客户端分别向渲染层和规律层注入WeixinJSBridge,WeixinJSBridge重点供给了以下几个办法: invoke:调用native API;invokeCallbackHandler:Native 传递 invoke 办法回调结果;publish:渲染层用来向规律业务层发送信息,亦便是说要调用规律层的事件办法;subscribe:订阅规律层信息;subscribeHandler:视图层和规律层信息订阅转发;setCustomPublishHandler:自定义信息转发;渲染层怎样向规律层通信?
渲染层向规律层通信的方式便是采用事件系统,以上便是完整的事件系统流程。研发者在DOM上经过@click绑定事件,WXML文件被编译的时候,会经过$gwx函数生成虚拟DOM,而后小程序执行的时候渲染层底层基本库会对虚拟DOM进行解析,事件绑定最后会以attr属性的形式生成到虚拟DOM中,因此底层基本库经过applyPropeties解析事件并经过addEventListener绑定到相应DOM并声明回调。
用户点击相应DOM时,Exparser组件系统接收到这个事件,而后起始执行回调。回调函数在规律层,事件的触发在渲染层,此时,小程序会经过setData发送数据到规律层,这个时候WeixinJSBridge就派上用场了,渲染层调用publish办法发送数据,规律层经过registercallback进行监听,并执行相应的回调。此时,渲染层到规律层的通信流程结束。
那规律层又是怎样将改变后的数据回传给渲染层的呢?规律层改变数据之后,一样是触发setData办法,而后渲染层经过subscribe进行监听,从eventname和触发事件时候记录的回调函数来判断是哪个事件被触发了,从而获取动态数据。
第三方小程序框架
WXML,WXSS都是小程序的原生研发语言,运用原生语言研发还是存在许多限制,尤其是17年小程序刚推出那会。因此呢,第三方小程序框架应运而生。第三方框架能够分为三大类。
第1类是预编译框架,预编译框架便是在执行前就进行编译。像我司在17年研发“转转二手交易网”的时候运用的wepy框架就属于预编译框架。预编译框架亦有有些显而易见的缺点,这类预编译框架要么是类vue,要么是类React,倘若后期vue或React再出有些新特性的话,预编译框架就要进行扩展编写;还有有些兼容问题,针对小程序本身不支持的有些属性,预编译框架需要进行兼容;
第二类是半编译半运行框架,像美团的mpvue便是此类框架,半编译指的是vue的template需要单独编译为wxml,半运行讲的是vue整体的特性都会在规律层中运行。为了符合小程序的渲染框架,修改了vue的框架;
第三类是运行时框架,像Remax便是运行时框架,它能够使研发者运用完整的React语法来研发小程序。由于小程序框架本身是不支持js直接操作DOM的,那Remax框架是怎样处理这个问题的呢?其实它自己复刻了一套操作DOM的API,例如appendChild,innterHtml等,然则它真正操作的并不是dom,而是data中的数据结构。从而达到了操作DOM的目的。使得自己真正成为了一个运行时框架;
结语
介绍到这儿,小程序的底层框架原理基本已然介绍完了,想跟大众分享的是,小程序确实和h5非常类似,其实它相当于一个借助了native强大功能的加强版h5,小程序并不奥秘,除了微X小程序之外,此刻各大超级APP都已然推出了自己的小程序,原理应该都大差不差。
本篇文案其实相当于一个学习笔记,作者本身非常想搞清楚微X小程序的架构,然则微X小程序并无开源,某次偶然的机会逛掘金的时候看到这篇小册,就全部学习了一下,这里感谢原作者!
参考
https://juejin.cn/book/6982013809212784676
|