前言
前端页面性能对用户留存、用户直观体验有着重要影响,当页面加载时间超过2秒后,加载时间每增加一秒,就会有大量的用户流失,所以做好页面性能优化,无疑对网站来说是一个非常重要的步骤。
那如何才能知道一个页面的性能情况呢?知道了页面性能情况后又如何进行优化呢?一个页面的性能指标非常多,面对一大堆性能指标,可能一个老手也一时间不知道从何开始分析。而且不同团队,负责的业务不同,性能分析的指标也不能够一概而论。打个比方说,对于一般的电商网站,一定会有很多图片,那图片加载的性能提升对网站的性能提升作用就比较大。而对于一些由表单组成的中台页面,提升图片加载速度的收益远小于电商网站。
总结来说,不同的团队有着各自不同的业务,业务之间千差万别,性能指标也不能一概而论,所以用一套统一的检测模型覆盖所有场景是不现实的。本文将介绍如何定制一个属于自己团队的性能检测平台。
先看下*采云的性能检测平台——百策
在聊性能指标之前,先讲一下Lighthouse。
Lighthouse
Lighthouse是一个开源的自动化工具,用于分析和改善Web应用的质量。运行Lighthouse共有4种方式,分别在Chrome开发者工具,Chrome扩展程序,NodeCLI和Nodemodule。百策主要基于Nodemodule方式,在其基础上进行扩展开发。
下图为Lighthouse检测页面性能的一个最终结果,可以看到其实指标已经比较完善了。
可能有人会问,为什么不直接使用Lighthouse。首先,由于不可描述的原因,国内直接使用Chrome开发者工具中的Lighthouse时,会一直处于Lighthouseiswarmingup状态。其次,Chrome扩展程序对于需要登录的页面也不支持。最后,对于前言中,某一些定制需求Lighthouse也不能全然满足,所以要基于Lighthouse进行定制,做一个满足业务要求的性能检测平台。
整体设计架构
下图是百策系统的一个整体架构
前端主要使用的是Antd和AntdCharts,包含常规页面的展示和部分性能走势图表的展示。服务端基于nestjs开发,接入Sentry做报警监控。helmet用于保护系统免受一些众所周知的Web漏洞影响。node-schedule用于每周定时计算已统计入系统的页面性能,并通过nodemailer发送邮件。Compression主要用于启用gzip。最主要的检测服务基于Puppeteer和Lighthouse开发。
百策采集页面性能数据的流程
百策系统监控页面的方式主要采用的方式是合成监控,对于什么是合成监控,可以参考此文章:蚂蚁金服如何把前端性能监控做到极致。总结来说,合成监控的优势就是:能够采集的数据更丰富,并且可以根据不同的场景定制不同的运行环境等。首先百策要根据不同的场景,比如*采云前台页面、*采云中台页面制定不同的检测模型。其次百策的主要目标是提升页面性能,并且需要保证环境和硬件条件一致的情况下对页面做性能比对,所以选择采用合成监控更加适合。
先看下ChromeLighthouse的架构图(图来源于LighthouseGit),主要基于4个主要步骤实现,分别是交互驱动,收集,审计以及记录组成,参考了ChromeLighthouse,百策的检测模型逻辑也主要由这4步组成:
1、页面交互后,发起请求调用服务。
2、遍历当前页面所需要的收集器,合并为一个总的收集器,并采集数据。
3、将第二步采集到的数据做性能计算和评分。
4、将性能检测结果存入数据库。
百策采集页面性能数据的实现方案
百策实现页面性能数据采集的方案主要依靠无头浏览器Puppeteer结合Lighthouse,Puppeteer是Chrome团队提供的一个无界面Chrome工具,人称无头浏览器,通过API来控制Node端的Chrome。百策的主要逻辑是在服务端起一个无需显示的Chrome,通过Lighthouse的API新建一个标签页并打开,Lighthouse会计算具体的性能指标,具体的检测逻辑可以参考下图。接下来我会用关键代码说明如何实现其中的关键步骤。
○开始入口
以下是百策价值1个亿的代码,主要流程如下,钩子函数是用于在页面打开的不同时间获取性能数据
○创建无头浏览器
创建无头浏览器和页面,并指定浏览器对应的宽高,指定运行的参数,关于浏览器的参数可以参考如下文章:PuppeteerAPI。可以将headless设置为false看到浏览器的创建和page的新建,本地调试可以使用。
○模拟登录
模拟登录的场景可以参考另一篇,“百策系统”实现模拟登录的实现,大致的实现逻辑如下:通过无头浏览器打开*采云登录页,通过PuppeteerAPI模拟输入用户名密码,并模拟点击登录按钮。根据同一浏览器下相同的域名共享Cookie的特性,再新开标签页打开需要检测的URL,便可以开始性能检测。
○打开页面
如何在Puppeteer中使用Lighthouse可以参考UsingPuppeteerwithLighthouse。下面的代码主要检测的是桌面端Web页面的性能,后续会放开更改检测环境的功能:可以根据*采云域名来判断页面是手机端还是电脑端,根据不同的系统环境,切换不同的浏览器参数。
○钩子函数
钩子函数实际是一个抽象类,在运行不同的Gathering时,对应的Class会实现该抽象类。钩子函数的主要功能在于不同时期注册回调,主要有2个钩子函数,beforePass和afterPass。beforePass的作用主要是在页面还没加载前先注册一些监听器,比如说想在页面load之后,就拿到DOM节点的深度,那就需要在beforePass中注册监听。afterPass主要是页面性能统计完成之后,返回结构化的数据。
○收集器的实现
百策总共有6个收集器,分别是DomstatsGathering,ImageElementsGathering,LighthouseGathering,MetricsGathering,NetworkRecorderGathering和PerformanceGathering。
每个收集器都会实现特定的收集功能:
DomstatsGathering:收集DOM相关的数据,比如DOM元素数量,DOM最大深度,document是否有滚动条等。ImageElementsGathering:收集所有的图片,并记录下图片的宽高,定位等属性。LighthouseGathering:收集Lighthouse相关的指标:比如FCP、LCP、TBT、CLS等等。MetricsGathering:收集JS事件监听数量,JS堆栈大小等。NetworkRecorderGathering:收集所有页面请求,包括状态码,请求方式,请求头,响应头等。PerformanceGathering:主要记录了window.performance下的一些数据,用于计算一些时间。以DomstatsGathering做为例子,详细说明如何获取页面检测数据。首先实现抽象类的2个方法:beforePass和afterPass。beforePass的实现逻辑是对page对象添加domcontentloaded时间点的监听方法,监听方法的主要功能是判断document是否有横向滚动条。afterPass方法主要是获取Lighthouselhr中的数据,分析并得到DOM最大深度,DOM节点数等。
等待所有Gathering都执行完成之后,数据就可以落库了。
○根据模型计算得分
数据入库后还要根据不同的模型计算不同的得分。前台页面重展示,并且图片加载会比较多,中台页面重表单提交,所以不同的模型一定有不同的计算逻辑。在*采云,前台页面我们使用的框架是Vue,中台页面使用的是React(部分页面由于历史原因用的还是jQuery)。所以大致可以根据框架来区分模型。判断框架是Vue还是React可以根据DOM是否包含_reactRootContainer和__vue__来判断。
以下是*采云前台模型,每一项都是一个检测指标,告警项只做提示,不实际扣分,前台主要以图片加载和展示为准,所以模型设计上,会更加侧重页面加载时间的关键指标,并且会着重考虑图片的展示。
前面内容主要介绍了百策的数据采集和评分功能,这也是百策最主要的功能。除了核心功能外,百策还有数据看版、提供性能解决方案、性能走势,性能对比,定时监测等功能。在这篇文章中我也不一一阐述了。
○自动检测
当然除了上面这些手动检测以外,百策也支持自动检测。自动检测的主要目的是统计所有收录在系统中的页面,统计哪些页面性能优化的最好,哪些优化欠佳。具体的逻辑:每周五2点会对所有收录在百策中的页面进行检测,将检测成绩最高的10个页面,检测成绩最低的10个页面,检测成绩进步最快的10个页面,自动检测的逻辑主要通过node-schedule实现。发送邮件可以ejs实现渲染模版,定义好模版后通过nodemailer发送即可。
○对接鲁班
关于鲁班是什么,可以参考这篇文章:前端工程实践之可视化搭建系统,用一句话来总结,可以说鲁班就是*采云的页面搭建系统。
在对接鲁班时,主要包括了鲁班页面的性能数据的录入和鲁班页面的录入(方便后续每周定时检测)。
鲁班性能数据的录入:和在鲁班生成页面时提供一个检测按钮,调用百策性能评分接口,生成检测数据。鲁班页面的录入:在鲁班的新页面上线的时候,会自动调用百策录入接口,新增的页面会被录入到百策系统中。结尾
如果你也想搭建一个属于自己的性能检测平台,并且恰巧看到了这篇文章,希望此文对你有所帮助。
本文最主要讲的是如何搭建一个性能平台。当你已经能够搭建性能平台之后,不妨可以思考下业务页面的检测模型。