最近做了一些移动端页面的首帧优化的事情,有很多心得和感想熏染,个中有很多共性的东西,总结成一篇文章希望可以帮助到更多业务,也希望引起读者一起谈论。
为何要做首帧优化
作为程序匠人,一贯在努力追求做一款好的产品,打磨各个细节,做好用户体验,而首帧是用户打仗到产品的第一个页面,是体验的重中之重。也正因是产品的第一个页面,转化率靠近100%,从ROI的角度来说,做好首帧优化也是一个很划算的deal。
做好首帧优化,至少可以带来以下好处:
建立用户好感度:良好的第一印象,提升品牌形象提升业务转化率:提升业务曝光率、点击率、带来更好的业务结果更小的资源花费、减少本钱:更长的首帧启动韶光意味着更多的资源花费,更多的本钱投入。优化首帧可以减少一些不必要的资源开销和损耗,节省技能本钱。首帧口径和衡量标准
▐口径
做优化前我们须要先想想,用户对首帧体验预期是若何的?首帧定义是什么,起始范围是什么。不同的口径会影响我们的指标,设计方案,事情量。定义了口径之后,我们可以确定优化事变范围以及边界。
Loading图:
即开始涌现loading、展现灰底图或是页面框架图,如果这页面展示也比较久的话,则解释用户交互涌现卡顿、假去世,迟迟没收到反馈,用户交互被壅塞,属于严重影响用户体验的行为。以是建议在展示骨架图之前,除了framework以外,不要有io、网络等耗时的前置依赖,也不须要有中转页的行为逻辑。
内容主体呈现:
即页面大部分的内容已经渲染出来,用户可以得到足够的信息,这是一个比较符合用户体感的口径,大多数业务选取的便是这个口径。不过不同业务对付“大部分”,“主体”的定义有所不同,业务可以结合自身需求进行合理选择:
对付“主体”定义:如头图、标题、相机取景器、对付“大部分”定义:如按照展示“面积”打算的,完全度80%、90%、100%(有一些分页加载策略的业务场景)页面可交互:
这个阶段表示页面已经完备渲染完成,并且用户可以进一步交互,如点赞、分享、收藏、加购等行为。
▐衡量标准
绝对耗时:
指定口径下的绝对耗时时长,单位一样平常是ms,多是用于单机线下的验证和比较,不同机型之间、不同场景下的差异较大,如高端机与低端机之间的差别可以相差好几倍,如要反应样本的整体性,多用分位值或者秒开率来衡量。
分位值/秒开率:
多用于线上不雅观测,反应样本的整体性和趋势,长尾数据、极度case不随意马虎被忽略该当让P90P95分位值,靠近于中位数,让整体样本的差异性小一些取值标准:
按照履历值:绝对耗时<500ms,一样平常情形下页面切换动画300ms,以是页面首帧500ms以内渲染完成,能够有一个较好的体验,google官方也建议页面尽可能在500ms以内完成冷启动。秒开率>95%+,即95分位<=1000ms参考头部竞品:能窥伺出同等业务繁芜度下,普遍用户能接管的一个范围通过屏幕录制办法可获取标准也并不是一成不变的,随着硬件性能不断提升、framework不断优化、亦或是业务形态的变革,而不断调度。如何剖析排查性能问题(以Android为例)
▐理解现状
首先要节制自身产品以及行业竞品的首帧数据,理解在行业中的一个排名情形,再决策是否要进一步做优化,做到什么样的程度。为了担保自身和竞品采取的同一种口径获取首帧耗时,我们这边采取了录屏的办法。
录屏剖析方案:在同一台手机上利用特定帧率录屏(如30fps,即1帧33ms),再通过数帧数的办法来打算出首帧耗时的韶光,录屏的越高越精确。
自动化脚本方案:
通过自动化录屏脚本工具、利用仿照点击 + OCR笔墨识别/图像识别的方案,识别首/尾帧、进而自动化天生耗时的中位数、均匀值。
▐理解事理
在剖析问题之前,我们要搞清楚系统是如何将首帧绘制在屏幕上的,理解了这些我们才能针对性的剖析问题。
Activity启动流程:https://juejin.cn/post/7063699032144609287View渲染流程:https://blog.csdn.net/u012216131/article/details/115704825https://www.cnblogs.com/mysweetAngleBaby/p/15549126.html
▐利用性能剖析工具官方工具:从代码、资源等细粒度的维度(如方法级别、事宜级别),来定量剖析程序对CPU、内存、网络IO等核心打算资源的花费情形,可以比较完全、全面的剖析启动过程,但这种办法得到的数据比较细碎、散点,须要经由一定的归纳、合并才能得到一个详细可履行的方案。
TraceView:Instrumentation 模式下采取 AddListener 的办法注册 MethodError、MethodExited、MethodUnwind 的回调来采集方法起止韶光;Sampling 模式下利用一个 SamplingThread 定时主权线程堆栈,通过对此的堆栈比拟近似确定函数的进入和退出韶光;虽然是官方供应的工具,但两种模式本身都存在比较大的性能损耗,可能带偏优化方向。CPU Profiler:整体通过 JVM Agent 实现,具有完成方法调用栈输出,且支持 Java、C/C++方法的耗时检测,上手比较大略,但其同样存在性能损耗较大的问题,且一样平常仅用于 debug 包,release 包须要额外添加 debuggable 的配置。Systrace:基于 Android 系统层的 Atrace 实现,Atrace 又基于 Linux kernal 层的 ftrace 实现,ftrace 在内核中通过函数插桩获取耗时;其自身性能损耗比较低、数据源丰富且具有较好的可视化页面,但其默认监控点较少,在 APP 自有代码中的监控点须要手动加入,比较麻烦。二方/三方工具:如果我们的页面是通过第二/三方的页面框架所构建,如weex/rn/flutter等框架。我们可以通过第二方框架供应的性能剖析工具、插件去剖析和归因。
rn:https://reactnative.dev/docs/performanceflutter:https://docs.flutter.dev/perf/ui-performancecompose ui: https://developer.android.com/develop/ui/compose/performance业务自定义工具:有时为了填补官方工具火焰图太细碎、难以聚类、须要花费更多韶光去剖析和追踪,我们可以根据业务视角、利用自定义的业务阶段/流程,去粗粒度的去剖析各个阶段的耗时。
埋点/日志工具:核心链路节点performance日志,如:页面视图创建、网络耗时、数据处理、渲染切面/插装代码工具:面向常用工具/事务/流程,对业务无侵入式的不雅观测和统计常见的优化方案和策略
剖析完缘故原由后,我们须要对不同缘故原由给出优化方案,首帧优化的核心思想用一句话总结是:在尽可能在短的韶光里准备好首帧渲染所须要最小的资源模型。环绕“最短韶光”和“最小的模型”两个中央思想下,总结了一些常见的优化策略:
▐预加载/缓存策略
在前置页面的合理机遇(一样平常是闲时)提前获取数据、下载资源,并解析,然后缓存到内存或者磁盘里,以便后置页面快速读取数据和资源。
这个策略可能带来以下副浸染:
提前获取的数据可能会引发做事端qps暴增,带来额外资源开销,和影响稳定性。如果页面点击率不高的话,缓存命中率会比较低,造成资源摧残浪费蹂躏的问题。可能会造成前置页面的性能受损。这个策略结合特定人群一起利用会更好一些。▐延迟初始化(与首帧无关的代码逻辑、资源可以在首帧渲染后进行初始化,详细的初始化机遇可以在利用时再初始化,如某些二级页面的创建、多余tab的创建等。
▐并行处理&异步化
并行处理:充分利用多核CPU,通过多线程并行处理耗时的任务,提升CPU的负荷。如容器初始化和数据要求解析可以同时进行。
异步化:一些比较耗时、IO任务,不要占用宝贵的主线程资源。
▐View渲染优化
Android里面ViewTree构建和渲染是比较耗时过程的,如下:
将 xml 文件解析到内存中 XmlResourceParser 的 IO 过程;根据 XmlResourceParser 的 Tag name 获取 Class 的 Java 反射过程;创建 View 实例,最终生成 View 树;View渲染:layout、measure、draw优化方案:
层级优化/布局优化 (merge嵌套),减少布局层级,减少递归深度利用ViewStub,延迟按需inflate,降落inflate耗时x2c:xml转code构建异步inflate,异步ui构建▐数据借用
为了加快数据获取,我们可以从前一个页面借用一部分数据过来将主体内容做添补,随后再用真实数据刷新。这个方案多适用于列表进入详情的场景。
这里的数据不仅包含笔墨和图片,也可以延伸到媒体播放器、camera取景器等其他一些文件流、数据流,乃至可以是widget组件(共享元素动画)。
▐分块渲染
如果页面元素比较多,数据量比较大,一次性要求加载的韶光比较长,这个时候我们可以通过分块的办法,将大页面拆成多少个小页面模块、将做事端接口拆成多少个小接口,各个页面模块独立渲染。可以有效降落做事端RT耗时,以及页面渲染耗时。
▐骨架图优化利用骨架图作为打底图和纯白底图比较,有告终构样式等信息,更加靠近于首帧的效果,正式数据刷新时,页面也不会涌现明显刷新,体验比较好。
线上验收
线下的优化,并不虞味着线上真实用户也能同步看到优化的结果,由于业务路径的差异、机型的差异,你线下的优化可能不具备普遍性,以是须要线上真实结果的反馈。
较全面信息的数据大盘建立:
包含:版本、设备分、业务场景、机型、韶光等尽可能多的数据维度的数据大盘,可以只管即便还原优化or劣化的信息全貌,供应更多的归因信息。
分位值(数据聚合种别):
长尾数据、小众case每每随意马虎被整体数据给覆盖,不敷以引起重视,为了我们该当分别剖析中位数、分位数。
AB实验:
这样做不仅能掌握变量确保优化项的严格有效,还能借此来不雅观察性能优化所带来的业务指标收益,这些都可以作为方案后续启动优化方向的参考辅导。
防劣化
人无完人,人都会失落误犯错,绝对不能把系统性能交给某一个人身上,一个人犯错概率高,一群人都犯错的概率低,该当交给一群人共同协作的机制和流程。
防劣化比较于优化是更能持久有益的,以是更该当在较早期建立起防劣化机制:
准入机制:禁止在启动核心阶段添加代码,统统代码添加须要走审查流程,启动阶段包含:Windvane.execute,Activity.onCreate,Fragment.onCreate/onCreateView审查机制:提审/测试/核准/灰度/上线遵照严格规范代码约束框架约束检讨工具CR规范线上监控大盘监控:趋势剖析分阶段监控:归因剖析监控告警:及时止损结语
▐持续迭代
首帧优化并非一挥而就,而是一个须要持续迭代与打磨的过程,在初期阶段优化空间相对较大,只须要投入一些不多的资源,即可看到较大的收益,但随着优化不断深入,到了中期阶段,就须要有相称程度的投入,去攻坚各个难点,聚少成多,才能看到收益。后期随着业务越来越繁芜,分支越来越多,要做防劣化事情,同时也要和业务一起做好风雅化管理,将有限的资源,分配给最优先级的业务,要做好ab实验管控、优先级管理、及时下线等。
▐做好繁芜度管理
为了将达到最优的启动速率,我们利用了各式各样的策略,将韶光和空间塞得满满的,但是这改变了原来的常规流程,带来了额外代码繁芜度提升,比如预加载策略,后面掩护同学须要考虑,预加载失落败以及成功两种情形,又或者是缓存策略,后面掩护的同学须要考虑缓存命中、不命中的情形,如果不断利用if堆积代码,那代码终极将无法掩护。以是我们须要通过框架来管理繁芜度,只管即便让业务层无感知。比如数据中间层,业务无需关心数据是否来自缓存还是实时要求,拿来利用即可。
▐全局意识
常日我们以启动速率来衡量启念头能。为了提升启动速率,我们可能会把一些原来在启动阶段实行的任务进行延后或者按需,这种办法能够有效优化启动速率,但同时也可能危害后续的利用体验。比如,如果将某个启动阶段的后台任务延后到后续利用时,如果首次利用是在主线程,则可能会造成利用卡顿。因此,我们在关注启念头能的同时,也须要关注其他可能影响的指标。性能上我们须要有一个能表示全局性能的宏不雅观指标,以防止局部最优效应。
参考资料
Profile性能追踪工具集:https://developer.android.com/studio/profileAndroid Performance 指南:https://developer.android.com/topic/performance/overviewRN Performance 指南:https://reactnative.dev/docs/performanceFlutter Performance 指南:https://docs.flutter.dev/perf/ui-performanceAndroid Activity的创建流程:https://juejin.cn/post/7063699032144609287View 的渲染机制:https://blog.csdn.net/u012216131/article/details/115704825Android 底层渲染事理:https://www.cnblogs.com/mysweetAngleBaby/p/15549126.html抖音Android启动优化之理论和工具篇:https://mp.weixin.qq.com/s?__biz=MzI1MzYzMjE0MQ==&mid=2247491335&idx=1&sn=e3eabd9253ab2f83925af974db3f3072
团队先容
我们是淘天集团-内容技能团队,专注于推动淘宝内容生态和电商体验的深度领悟。我们致力于为环球用户供应丰富、多样性、高品质的购物内容体验,旨在通过技能创新,更好地连接用户和商品,以提升用户的购物满意度和平台的商业代价。通过尖端技能提升内容创作、分发与消费的效率,赋能内容创作者、商家与消费者,构建一个繁荣、康健、可持续发展的内容生态圈。