48
作者:九思

你好,我是九思,来自腾讯前端技术部,擅长前端监控、工程化相关技术。此篇文章将围绕前端性能优化中监控问题展开讨论。

首先我们要知道,页面打开快不快,不是在电脑或手机上的打开速度说了算,也不是测试同学测试的结果说了算,而是真实用户使用的时候说了算。

那么如何去监控用户真实使用时的页面性能呢?本文将做细致介绍(建议收藏)

前端监控需要注意什么?


首屏

页面上线后,我们最关心用户打开页面的速度,通常就是首屏。

静态资源

页面加载离不开静态资源的加载,包括 js、css、img、video、font 等,在如今盛行 SPA 的场景尤为重要,比如活动页面会有很多图片,我们通常会开发一些模板,由产品/运营同学来配置,而图片多大合适是比较难确定的,网速越来越快,大家对清晰度要求也越来越高,此时就可以通过监测这些图片的加载速度来酌情优化。

API 请求

数据是页面中相当重要的元素,可以说没有数据,你的页面几乎没有使用价值(纯静态除外)。当然这里我们只能粗暴的监控整个请求的总时间,纯前端无法监控各个阶段时间,但这对于线上应用也很重要。

其他测速

实际上线后,不同的应用可能会有不同的测速诉求,比如:视频从加载到播放的时间,此时可以自定义一些测速点,利用之前讲述的打点方式来上报。

如何监控静态资源?


这块其实还是比较简单的,只需要利用 PerformanceResourceTiming 即可,并且它的兼容性极高,可以覆盖到几乎所有场景。

图片

实际监控时,可以分两种场景,如果支持 performanceObserver 可以实时监听,否则使用定时器方式,此外需要将此代码放到页面最顶层,否则无法监控到这段代码之前的资源加载。

 const typeList = \['script', 'link', 'img'\]; //   
 const staticTime = {};  
 const dealTime = (entries) => {  
 for (let i = 0, l = entries.length; i < l; i++) {  
 const entry = entries\[i\];  
 if (typeList.indexOf(entry.initiatorType) !== -1) {  
 staticTime\[entry.name\] = entry.connectEnd - entry.connectStart;  
 }  
 }  
 }  
 if (typeof window.PerformanceObserver === 'function') {   
 const observer = new window.PerformanceObserver((list) => {  
 dealTime(list.getEntries());  
 });  
 observer.observe({ entryTypes: \['resource'\] });  
 } else {  
 setInterval(() => {  
 const allEntries = performance.getEntriesByType('resource');  
 const entries = allEntries.slice(allEntries.length);  
 dealTime(entries);  
 }, 5000);  
 }

entry 部分数值

connectEnd: 32.63499999593478

connectStart: 32.63499999593478

decodedBodySize: 160302

domainLookupEnd: 32.63499999593478

domainLookupStart: 32.63499999593478

duration: 37.54000000481028

encodedBodySize: 23876

entryType: "resource"

fetchStart: 32.63499999593478

initiatorType: "link"

name: "https://stackpath.bootstrapcdn.com

nextHopProtocol: "h2"

redirectEnd: 0

redirectStart: 0

requestStart: 44.60999999719206

responseEnd: 70.17500000074506

responseStart: 65.40999999560881

secu reConnectionStart: 32.63499999593478

serverTiming:[]

startTime: 32.63499999593478

transferSize: 23971

workerStart: 0

图片

API 监控


关于 API 的监控,可以采用重写 XHR 或者 fetch,这样可以适用任何的框架、请求库。时间计算则是通过打点的方式,如果只是固定项目监控,也可以直接采用打点的方式。如果采用重写的方式,不仅可以监控请求的时长,还可以监控请求的成功失败率。

打点最简单的方式:

const startTime = Date.now();  
fn() // 假设这里是同步执行  
const timeCycle = Date.now() - startTime; // fn的执行耗时

除了以上这几点,前端监控的实操中我们还应该考虑到上报、限流以及如何处理这些性能数据。

点击链接查看详情:https://ke.sifou.com/course/1...
图片

上报


发送请求

发送请求我们很容易想到适用 fetch / XHR,当然也可以使用自动发起请求的 HTML 标签,比如 script、link、img。上报数据虽然可以拿来分析页面的真实运行数据,但有一点要注意的是:不能影响当前页面的运行或最小程度的影响。

是否可以直接用 fetch/XHR 呢?答案是否定的,因为上报的域名和页面的域名基本是不同的,所以这里需要可以前端跨域的方式。

说到跨域,浏览器的 src 属性标签基本都可以,到底用哪个呢?原则上要适用对页面影响最小的那个,诸如 Script、link 这些标签之前有讲述,他们都会对页面的运行造成影响。

img 变成了较为合适的方式,构造图片打点不仅不用插入DOM,只要在 JSnewImage 对象就能发起请求,而且还没有阻塞问题,在没有js的浏览器环境中也能通过 img 标签正常打点,这是其他类型的资源请求所做不到的。

在所有图片中1px x 1px 大小,gif 体积最小,相较 BMP/PNG,可以节约41%/35%的网络资源,所以适用 gif 相对是最佳选择。

限流

页面的性能数据,每次访问都会有,如果你的项目 pv 有一定量级,那么处理起来就会相当耗费资源,而且这些数据我们最终是求平均值或者分位值,所以没必要全量上报。那么我们可以在上报前做一些限流处理。

更多内容


除了以上这几点,前端监控的实操中我们还应该考虑到如何处理这些性能数据,主要有取中位数、平均值、分位数等做法,由于篇幅有限此处不做详细介绍。

最后,如果这篇文章给你带来些许有价值的理解,欢迎点赞、分享,更多内容可翻阅我的付费专栏《前端性能优化12问》。

点击链接查看详情:https://ke.sifou.com/course/1...
图片


思否编程
5.1k 声望27.2k 粉丝

思否编程是由中国新一代开发者社区 SegmentFault 思否孵化的在线编程培训平台,通过提升开发者 IT 职业技能,帮助开发者获得成功