【移动应用开发技术】微信开发之解密与思考Rax 小程序运行时方案_第1页
【移动应用开发技术】微信开发之解密与思考Rax 小程序运行时方案_第2页
【移动应用开发技术】微信开发之解密与思考Rax 小程序运行时方案_第3页
【移动应用开发技术】微信开发之解密与思考Rax 小程序运行时方案_第4页
【移动应用开发技术】微信开发之解密与思考Rax 小程序运行时方案_第5页
免费预览已结束,剩余2页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】微信开发之解密与思考Rax小程序运行时方案

在下给大家分享一下微信开发之解密与思考Rax小程序运行时方案,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!2020年3月,暨支持编译时方案之后,Rax小程序发布了支持运行时方案的版本。截至目前,Rax仍是业界唯一一个同时支持编译时和运行时方案的小程序开发框架。具体如下:回顾编译时方案介绍运行时方案之前,我们再回顾下什么是编译时方案。顾名思义,编译时方案侧重于编译,这其中的代表框架是Tarov2.x。其通过静态编译的方式,将JSX转换为小程序的模板语言(即WXML/AXML等),再辅以轻量级的运行时JS代码,抹平小程序生命周期和React生命周期的差异,使用户能够以熟悉的ReactDSL进行小程序开发。Rax的编译时方案原理与Tarov2.x类似,关于实现细节,可以参考之前的文章Rax转小程序链路原理解析(一)及Rax小程序编译时方案原理解析。区别于编译时方案,运行时方案侧重在运行时实现渲染能力,不依赖静态编译,因此几乎没有语法限制,这也是其最大的特点。下面就来看一下运行时方案实现的原理。诞生基础小程序的底层实现实际上也是基于Web技术,但是反映至开发者层面,与Web却又大相径庭。在小程序中,逻辑层和视图层隔离,逻辑层通过唯一的setData方法将数据传递至视图层触发渲染,视图层则通过事件的方式触发逻辑层代码,其架构如下图所示。相比Web开发时开发者可以通过JS调用浏览器提供的DOM/BOMAPI随心所欲操作渲染内容,小程序的架构更加封闭也更安全,但也意味着Web代码无法直接在小程序上运行。对于现代的前端框架(React/Vue)来说,底层基本都是通过调用DOMAPI来创建视图。而小程序的视图层模板是需要开发者事先写好的,这意味着动态创建DOM的方式在小程序中不被允许。但是,小程序的自定义组件具有的『自引用』特性为动态创建DOM打开了突破口。所谓自引用,就是自定义组件支持使用自己作为子节点,也就意味着通过递归引用的方式,我们能够构造任意层级和数量的DOM树。举例来说,假设一个小程序自定义组件element的WXML模板如下所示:<view

wx:if="{{r.tagName

===

'view'}}"

id="{{r.nodeId}}">

<block

wx:for=“{{r.children}}”

wx:key="nodeId"

>

<element

data="{{r:

item}}"

/>

</block></view><text

wx:elif="{{r.tagName

===

'text'}}">

{{r.content}}</text>复制代码注意到,element在模板中递归引用了自身,并通过条件判断终止递归。那么,当逻辑层通过setData传递了以下一份数据过来时:{

"nodeId":

"1",

"tagName":

"view",

"children":

[

{

"nodeId":

"2",

"tagName":

"text",

“content”:

“我是?"

},

{

"nodeId":

"3",

“tagName":

"text",

"content":

"rax"

}

]

}复制代码最终呈现出来的视图便成了:<view>

<text>我是</text>

<text>rax</text></view>复制代码通过这种方式,我们巧妙地实现了在WXML模板固定的情况下,根据传入的setData数据来动态渲染视图的能力。而这,也正是运行时方案能够诞生的基础。基本原理Rax的运行时方案脱胎自kbone——微信官方推出的小程序与web端同构解决方案。kbone的设计原理可以参考其官网介绍,简单总结就是通过在逻辑层模拟DOM/BOMAPI,将这些创建视图的方法转换为维护一棵VDOM树,再将其转换成对应setData的数据,最后通过预置好的模板递归渲染出实际视图。从DOMAPI到维护VDOM树的过程基本原理并不复杂,createElement/appendChild/insertBefore/removeChild等对应着基本的数据结构的操作。熟悉Rax的同学应该知道,为了支持跨端,Rax有driver的设计。实际上,我们完全可以针对小程序端再编写一个driver,根据上述原理实现其接口API即可。但我们最后的选择还是通过更底层的模拟BOM/DOMAPI来完成了整个渲染机制。这么做的考量是,第一,基于kbone开发,这是最快的一套方案,小程序端的driver只需复用web端的driver-dom即可,毕竟底层的document和window变量都已经模拟好;第二,则是因为我们想为开发者提供更贴近web的开发体验。这套方案意味着开发者除了使用JSX之外,也是支持直接使用BOM/DOMAPI创建视图的,灵活度会更高一点。我们把目光拉长到整个市面上的小程序运行时框架,remax通过react-reconciler直接从VDOM层和小程序对接(类似上面说的Rax小程序driver设计),而kbone和Taro3.0都选择通过模拟Web环境来实现渲染。这也与框架开发人员的设计意图有关,见仁见智。Rax小程序运行时方案的基本原理图如下所示:事件系统Rax小程序运行时中,模拟DOM/BOMAPI的库为miniapp-render,其支持的API如下:除了处理渲染数据外,另一个比较重要的事情便是事件系统。其通过EventTarget基类实现了一套完整的事件派发机制。逻辑层DOM节点均继承自EventTarget,通过唯一的nodeId来收集自身绑定事件。视图层模板上的每个内置组件都会绑定nodeId,并监听所有可触发的事件,比如一个简单的view标签,会将bindtap/bindtouchstart/bindtouchend等事件都进行绑定。在事件触发时,通过event.currentTarget.dataset.nodeId获取到目标节点id,再触发该节点上用户绑定的对应函数。工程设计Rax小程序运行时的工程主体流程follow了RaxWeb的设计,Web端Webpack打包出的JSBundle可以在小程序运行时中复用。我们通过插件将miniapp-render模拟出的window和document变量注入该bundle,再生成一个固定的小程序项目骨架,在app.js中加载JSBundle即可。其整体工程结构如下图所示:MPAorSPA?以上架构是逐步演进的结果。最初,我们使用了webpack的多entry模式打包运行时小程序代码,也就是每个页面都会作为一个entry独立打包。这使得从行为上来说小程序更像一个MPA。这带来的问题就是页面间公共依赖的代码不在同一内存中执行,与原生小程序表现不符。这个差异导致我们最终决定变更工程打包模式。目前版本的Rax运行时小程序更符合SPA的形式,所有的业务代码都打包到了一个JS文件中。我们将Rax工程入口的rax-app包在小程序运行时上的链路做了一定改造,其在初始化时会根据路由返回各个页面的render函数,该render函数创建root节点(document.createElement)将对应的Rax组件挂载至其上,并将root节点append到body节点(document.body.appendChild)。小程序每个页面在onLoad生命周期中,会创建一个独立的document并设置为全局变量,然后调用其对应的render函数进行各个页面的独立渲染。性能调优从上面的小程序运行时原理来看,其性能相比原生是存在一定差距的,这主要由以下几个方面造成:第一:逻辑层运行完整的Rax+通过模拟DOM/BOMAPI处理VDOM并生成setData数据,需要消耗更多的计算时间;第二,相比原生小程序需要传递更多setData数据,如果容器层数据序列化能力较弱,会大大增加数据传输耗时;第三,视图层通过自定义组件递归动态生成视图,而我们知道递归动作本身就是一个性能损耗点。此外,由于无法预先知晓用户需要绑定的属性和事件,自定义组件模板中只能将所有属性和事件预先绑好,这导致小程序运行过程中会触发很多无用的事件,进一步加重负担。经过我们的benchmark计算,在支付宝小程序平台上,运行时小程序框架(包括Rax/Taro/Remax等)与原生小程序存在约40%的性能差距。Rax小程序运行时发布后,经测试其性能相比其他运行时框架存在着较为明显的差距,于是我们启动了性能调优的专项计划。通过以下方面的重构,成功将Rax小程序运行时小程序的性能拉升至业界领先水平,与Taro/Remax基本处于同一水平线。更新数据精确化。在旧版本中,setData的数据是全量更新的,虽然有dom子树分割批量更新的设计,但是数据传输仍然存在大量冗余。重构版本中,Rax增加了节点渲染判断,未挂载节点无须触发更新;将所有更新收拢至顶层root节点统一批量处理,并且通过精确计算数据更新的path,实现局部更新。比如某次更新节点的class属性时,setData的数据可能是:内置小程序组件无需维护其属性列表,而是根据用户传参直接赋值。旧版本中,我们维护了所有内置组件的属性,在获取属性值的时候均需要调用domNode.getAttribute,具有一定性能开销。重构版本Rax直接根据用户传参给属性赋值,并将默认值设置的操作移至视图层WXS/SJS中处理。更新miniapp-render中的数据结构。经过梳理,Rax移除了冗余的tree数据,重写了getaElementById等API;重构了attribute、classList等类;使用了更符合场景需要的Map/Set等数据结构,提升了整体的数据处理性能。渲染模板优化。在支付宝小程序中,Rax使用template进行递归调用;在微信中,Rax使用template调用element再调用template的形式以避免微信端递归调用template的层数限制。在模板中,我们尽量使用templateis语法进行判断,减少a:if/wx:if条件判断,提升模板递归时的性能。混合使用无论是出于旧有业务的迁移,或者是出于性能考虑,Rax小程序运行时中都存在着混合使用的需求。目前,Rax已经打通与小程序内置组件、小程序自定义组件、小程序页面、小程序插件混合使用的能力。这其中,使用小程序自定义组件是最为复杂的。与小程序自定义组件混用在Rax中使用小程序自定义组件,其引入路径需要与usingComponents保持一致(例如importCustomCompfrom'../components/CustomComp/index')。在编译阶段,Rax工程使用Babel插件进行代码扫描,检测到JSX中使用的某个组件是小程序自定义组件(根据其引入路径是否存在同名axml文件)时,会将其使用到的属性和事件进行缓存,然后通过webpack插件动态生成至递归模板中。在运行时中的创建节点阶段,通过查询缓存判断节点是否为自定义组件。若是自定义组件,则其渲染数据中会插入缓存中的属性,并且绑定事件至该自定义组件实例。与编译时组件混用(双引擎混合)通过Rax小程序编译时方案产出的组件,从使用形态上来说,可以直接视为小程序自定义组件。而Rax工程加强了运行时与编译时的联系,当在Rax

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论