本文作者:ivweb 朱灵子
本文主要介绍react-native通用化建设以及对react-native项目进行性能优化的方案,总体来讲主要围绕以下几个方面展开:
React Native通用化建设主要做了一下几个方面的事情:
接下来重点介绍react-native线上离线包优化机制以及react-native项目bundle本地分包方案
为了实现React-Native线上项目react-native版本与h5版本的自由切换,同时合理地管理好不同项目不同版本的react-native离线包与h5离线包,我们的方案是将h5离线包和react-native bundle文件打在同一个离线包中(放在同一个bid号的离线包中)。
若后台url地址下发中携带md=rn字段,同时离线包中可以检测到react-native bundle文件并且app版本号符合react-native离线包中所配置的离线包生效所要求的app版本范围,则优先加载项目react-native版本。若不满足上诉几点要求,我们则优先加载react-native bundle本地文件或直接走项目h5线上资源。
如下图所示为离线包优化整体流程图
下图为faceBook推出的react-native消息流页面加载耗时分布图
从这张图中我们可以看出,RN加载速度最大的瓶颈其实在于图中绿色的区块JS init+Require,这块时间也就是JSBundle的执行时间;同时若多个项目同时上线,多个业务却不共用基础模块,jsbundle文件会越来越大,app的离线包文件负荷也会越来越大
基于以上提出的两个问题,我们的解决方案是:react-native bundle本地分包策略
一般基础包压缩以后有150k左右,而较复杂的业务所分离出的业务包体积最多也不到100k。React-native打包方案是一套类似 CommonJS的轻量require/define模块系统,保持轻量和对RN特性关注也是RN不使用webpack和broswerify而是自己实现打包的原因。要实现react-native bundle本地分包,我们要做到依赖引用(业务包去 require 基础包中的模块),因此我们需要把基础包中包含的模块列表导出来给业务包打包时使用。
以下为已实现的react-native bundle本地分包方案的主要思路:
用户在访问react-native view时,客户端检索到离线包中的业务包bundle文件以后后与基础包文件进行简单的合并,然后注入Jscontext&&runApplication, 最后展示React-Native view
使用这一打包思路实现bundle本地分包的优势
以上打包方法确实解决了app中react-native bundle打包以后文件包体积过大的问题,但是却没有解决react-native bundle加载以及执行时间过长的问题,基于这一点我们提出的方案是
预加载基础包,再运行业务包,而且多个react-native业务切换的时候可以直接复用基础包
该方案的可行性分析:
以下为短视频react-native项目的线上数据,主要从首屏时间、cpu、内存以及crash率等方面和h5项目进行对比
通过对比可以发现,react-native项目和h5相比在首屏时间以及fps等方面存在较大的优势,但是其在内存方面存在劣势,而且在首屏时间方面的优势还存在较大的提升空间
接下来我们从首屏加速、性能优化这两个方面进行分析,主要的优化策略如下图所示:
首屏时间方面的优化主要有
接下来具体介绍针对安卓端提出的安卓端react-native上下文预加载优化
使用React Native开发混合应用的过程中,我们第一次进入页面(React Activity)会有一个短暂的白屏过程(在真机上近 1秒,在模拟器上比较快,在 200毫秒左右),而且在完全退出后再进入,仍然会有这个白屏。
安卓端打点后可以发现在ReactActivity的onCreate方法中,耗时最多的是 createRootView()和startReactApplication()这两个操作 对于安卓白屏的问题我们的优化方案是:提前创建ReactRootView进行render,在runApplication之后直接将创建好的rootView挂载在React-Native view上去
这里是安卓react-native源码时序图
具体来讲就是将oncreate方法中的createRootView()和startReactApplication()这两个耗时比较多的方法提前到上一个activity中进行处理或者在整个app启动以后进行处理
这一点我们可以借鉴qq空间团队的思路,主要优化思路为:客户单预初始化上下文与cgi预加载的结合,主要流程图如下图所示:
在app打开以后自动预初始化客户端React上下文 在点击react-native入口以后直接复用客户端初始化好的rootView,与此同时客户端发起cgi请求,预加载cgi数据并缓存,前端直接读取缓存数据 【注:由于react-native不存在渲染html文件,所以我们通用的preload在rn这里不太适用】
性能优化方案
最新版rn源码已改为模块按需加载的模式,升级react-native客户端与js端的源码至最新版,可以很大程度上降低react-native项目运行的内存损耗,同时还可以降低app运行的 crash率
减少绘制,优化CPU
我们在测量短视频项目启动时的内存变化量时发现了一个有趣的现象:每次测量时是否杀掉进程重新开启app来进行测量和不杀进程进行多次测量的内存变化量相差较大
为什么会存在这个问题呢?因为短视频项目使用的是listView组件ListView 首次加载时都默认最多加载 initialListSize 个子项,所以能保证启动速度,但是在滑动的过程中会逐渐向 ListView 中添加子项,新出现的子项都是通过创建新的 View,而完全没有复用的过程。所以若应用中ListView 的子项数量特别多,ListView 滑动过程中内存会逐渐上涨,离开react-native-view后内存也不会快速释放,所以就是出现之前内存测量的奇怪问题
而listView是rn最常用的组件之一,优化ListView势在必行,这里我们提出两种方案:
感谢您的阅读,欢迎提出问题以及修改建议。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。