一、背景与挑战
H5开发因其跨平台兼容性而备受青睐,为了支持业务的快速发展,H5页面在应用程序中的使用比例不断增加。随着应用不断丰富的功能,H5页面的复杂度也随之提升,这对应用的性能以及质量保障工作提出了更高的要求。
性能测试方案: 我们迫切需要一套H5性能测试的自动化方案,对网页或应用程序的加载速度、响应时间、资源占用等方面进行测试,发现潜在的性能问题并进行优化,提升用户体验和页面加载速度;
自动化完成验证:需求快速迭代的前提下,我们需要有自动化的验证的能力,减少人工参与的成本;
防劣化测试:通过对竞对的页面进行对比验证,形成一套当前应用的准出标准,并在后续迭代中持续执行防劣化测试。
二、方案与目标
在构思初始方案时,我们在行业内寻找并比对类似的性能收集工具,Firebug、Fiddle和HttpWatch等。这些工具确实能满足一定的需求,但执行过程复杂,不能很好的管理性能测试结果,不能分析结果,所以需要一个H5性能自动化测试平台。所有的操作都能平台化,降低使用成本。
最后我们敲定了一键测试的解决方案,就是用户只需提交一个Url或者结合我们现有的UI自动化进行点击页面跳转的同时,收集性能数据,就可以得到一份完美的报告。具体目标时序图如下:
梳理出实现链路中的重点和难点,我们需要着重完成以下功能:
自动化任务与mitmproxy结合:通过APP端的UI自动化任务驱动mitmproxy收集页面的各个资源的加载情况的请求流数据,并且需要保证各个页面各个应用之间的资源数据不会相互影响;
页面请求流转化为瀑布流:我们通过mitmproxy手机的页面资源的.har文件,是不易阅读的。希望能转换成可阅读的瀑布流的样式,能够很明显看出页面涉及到的资源以及各个资源的耗时情况;
通过URL对页面进行评分:APP端的UI自动化任务页面跳转时可以获取到页面的URL,通过URL调用Lighthouse工具,对页面进行综合评分。
通过页面的综合评分可以看出页面的性能是否达到预期或者达到竞品的性能水平。然后结合请求瀑布流信息来分析未达标的核心耗时在哪些资源,以及资源之间请求顺序是否合理,同时也能看出哪些接口影响页面最终加载完成时间。
三、能力建设
基于以上方案与目标,我们详细设计了整个平台的架构。利用现有的移动测试平台的APP的UI自动化能力,运行UI的同时完成性能的收集与分析,具体架构全景图如下:
下面我们分别详细讲解下每个部分是如何实现的。
3.1 自动化与mitmproxy结合
为什么我们会选择mitmproxy来获取页面上各种请求数据流?首先它是用python语言编写,具跨平台兼容性并支持命令行操作,更重要的是它可以通过script脚本来处理抓包的输出流,实现诸多自定义的操作。相比类似工具tcpdump,其功能更强大。除了H5的性能测试之外,我们当前的埋点自动化测试方案也是基于mitmproxy来收集埋点数据,并通过自定义的规则完成埋点数值的收集与校验。
当前,我们在平台上使用Appium运行UI自动化测试,通过编写关键字的形式来实现自动化脚本的执行。借助我们现有的自动化能力,我们能够通过UI自动化驱动来收集性能数据。为此,我们封装了一个名为WebClick的伪代码关键字,专门用于H5页面性能测试。
在实际操作中,当程序运行自动化脚本时,WebClick关键字会触发页面点击操作,同时后台会自动收集页面每个请求的数据流。通过这种方式,我们能够在不增加额外复杂度的情况下,全面监控和评估H5页面的性能表现,为用户提供详细的性能报告和优化建议。
考虑到我们当前多款APP在多台设备上同时运行的复杂场景,为了防止各个应用和设备之间的数据相互干扰,我们使用mitmproxy并通过自定义编写的脚本对收集到的输出流进行精细化分类管理。具体来说,我们主要通过AppId和设备唯一标识(Device ID)对数据进行分类,将同一个AppId和设备ID的数据存储在对应的.har文件中。
此外,为了确保数据的准确性和独立性,每次打开新页面之前,我们会先检查并确认前一个页面的数据处理已经完成,然后清空当前文件,以防止不同页面的数据流相互影响。这一过程确保了数据的隔离性和完整性,使得每个.har文件仅包含特定AppId和设备ID的相关数据,从而避免了数据混淆和干扰。这样处理之后,我们能够在多应用、多设备并行运行的环境中,有效地管理和处理性能数据,确保数据的准确性和可靠性,为后续的性能分析和优化提供坚实的基础。
那么针对以上流程中每条数据流的request和response具体是怎么处理的呢?解析出request和response中各个关键字段,详见下:
3.2 页面请求流转化为瀑布流
在我们获取到请求数据流的.har文件之后,为了更加清晰明了地查看所有请求流的情况,我们借助于harviewer工具。在我们的平台前端工程中,我们创建了一个web应用(webapp),并将harviewer所需的依赖引入到前端工程中。
具体来说,我们在前端工程中创建了一个专门用于展示瀑布流的页面。这个页面能够将.har文件中的请求数据转化为直观的瀑布流图表。通过这种方式,用户可以清晰地看到每个请求的详细信息,包括请求的开始时间、持续时间、各个阶段的耗时以及请求和响应的具体内容。如下图:
友好的界面:可以清晰的看到每个请求的信息,如:URL、方法、状态码、大小、时间戳等;最上面的饼图还能分析出各个资源以及耗时的占比。
时间线视图:显示了页面加载过程中各个请求的时间顺序和耗时,有助于找出可能导致性能问题的原因;
详细信息:可以深入查看每个请求的详细信息,包括请求头、响应头、cookies等;
根据以上图片显示,页面完全加载完成的时间为2.12秒,这在对标竞品中处于中等偏下的水平。为了提升页面加载速度,我们可以从以下几个方面进行优化:
首先,资源体积占比最大的部分是JavaScript文件,其中有两个JavaScript资源的加载时间较长。我们可以通过代码拆分、异步加载、减少不必要的库和插件等方式来优化这些JavaScript文件的加载时间。其次,页面调用的一个接口耗时较长,这可能是由于服务端响应时间过长导致的。我们需要从服务端入手,优化接口的响应速度。可以考虑的措施包括:优化数据库查询、使用缓存机制、提高服务器的处理能力等。此外,还有一个静态图片的加载时间也较长。我们可以通过压缩图片、使用现代图片格式(如WebP)、启用延迟加载(lazy loading)等方式来减少图片的加载时间。
3.3 通过URL对页面进行评分
我们仍然依赖于现有的UI自动化功能,在运行自动化测试的同时,还可以借助Lighthouse对页面进行性能评分。Lighthouse大家可能都知道,是用于分析网络应用和网页,并为研发人员提供优秀实践的建议。传统上,大家使用Lighthouse都是通过手动命令行的方式进行操作。为了提高效率和准确性,我们决定将Lighthouse集成到现有的Appium自动化框架中。
通过Appium的API,我们可以自动化获取H5页面的链接,并自动化地唤起无头浏览器来收集性能评分。然而,由于每次测试结果可能存在偶然性,并且对网络环境的依赖较大,我们的方案是多次运行测试,然后通过程序计算中位数值作为最终的性能评分结果。这种方法不仅提高了测试的准确性和可靠性,还大大简化了性能评估的流程。
此外,我们还可以将性能评分结果与上面章节的请求瀑布流结果结合在一起,生成综合的测试报告。
四、应用与实践
4.1 防劣化测试应用
想要进行防劣化测试,首先我们需要制定对应的目标。业界常用的指标有:
针对我们当前的应用页面,经过一轮优化之后,我们初步制定了产品的性能目标:所有资源在请求瀑布流中的加载完成时间应控制在3秒以内,Lighthouse评分应保持在60分以上。为了更好地监控和评估性能优化的效果,我们可以将每个页面的历史评分绘制成趋势图。通过这种方式,我们能够直观地观察到近期业务代码改动对页面性能的影响。
4.2 页面性能优化实践
4.2.1 交互优化
在注册首页的最初版本中,Largest Contentful Paint(最大内容绘制时间,LCP)达到了3601毫秒,而Total Blocking Time(总阻塞时间,TBT)也高达700毫秒,导致页面整体评分仅为45分左右。通过与业界的性能数据进行对比,我们发现页面存在较为严重的性能问题。为了解决这些问题,我们进行了以下优化措施:
优化定位交互,缓解总阻塞时间:原来的交互设计在初始化时直接弹出定位弹窗,这不仅阻塞了元素的渲染,还可能引起用户的抵触心理。优化后,我们采用了其他手段自动获取定位信息,从而减少了阻塞时间并提升了用户体验。
减少页面接口阻塞:瀑布流数据可以看到某接口耗时较长且阻塞页面。通过优化后端接口和前端请求,减少了页面加载过程中接口调用的阻塞时间。我们对接口进行了合并和优化,减少了不必要的网络请求,从而提升了页面的加载速度。
优化后页面LCP从3601降低至2667,下降26%;FCP从2128降低至956,下降55.1%;TBT从700毫秒降低至400毫秒。整体页面评分提高到60分以上。
4.2.2 资源优化
在我们的APP中多个页面中,通过请求瀑布流数据可以看到,JavaScript、CSS等资源的加载时长超过了700毫秒。经过排查,我们发现仍有优化空间,主要优化方向如下:
Resource Hits资源预请求
整体资源优化前后对比:
会员页、流水页、任务中心页、个人资料等多个页面整体的加载时长有7.41% - 16.39%的减少。类似的优化还有很多,我们就不一一举例了。
五、未来展望
持续集成与监控告警能力: 在代码提交之后,自动化系统将判断所影响的页面,并运行相应的性能测试。如果性能结果低于预设的阈值,系统将自动触发告警通知相关团队,确保问题能够及时得到处理和解决。通过这种方式,我们能够在每次改动后实时评估性能变化,确保页面性能的稳定性和优化。
AI识别优化方向:通过收集的数据,借助于ai的能力,通过训练模型,AI能够识别出常见的性能问题模式,并根据代码改动评估可能会导致性能下降,能够自动识别出现问题的代码以及给出优化方向。