Web性能监控,你学会了吗?
前言:为什么需要监控
web 的性能一定程度上影响了用户留存率,Google DoubleClick 研究表明:如果一个移动端页面加载时长超过 3 秒,用户就会放弃而离开。BBC 发现网页加载时长每增加 1 秒,用户就会流失 10%。
RAIL
模型来衡量应用性能,即:
Response
、
Animation
、
Idle
、
Load
,分别代表着 web 应用生命周期的四个不同方面。并指出最好的性能指标是:100ms 内响应用户输入;动画或者滚动需在 10ms 内产生下一帧;最大化空闲时间;页面加载时长不超过 5 秒。
-
响应速度:页面初始访问速度 + 交互响应速度 -
页面稳定性:页面出错率 -
外部服务调用:网络请求访问速度
1.页面访问速度:白屏、首屏时间、可交互时间
这两个指标浏览器已经标准化了,从 performance 的
The Paint Timing API
可以获取到,一般来说两个时间相同,但也有情况下两者不同。
我们假设当一个网页的 DOM 结构发生剧烈的变化的时候,就是这个网页主要内容出现的时候,那么在这样的一个时间点上,就是首次有意义的渲染。这个指标浏览器还没有规范,毕竟很难统一一个标准来定义网站的主体内容。
first meaningful paint
:https://docs.google.com/document/d/1BR94tJdZLsin5poeet0XoTW60M0SjvOJQttKT-JK8HI/view
2.页面稳定性:页面出错情况
-
资源加载错误 -
JS 执行报错
3.外部服务调用
-
CGI 耗时 -
CGI 成功率 -
CDN 资源耗时
-
监控的分类?
合成监控
Lighthouse
、
PageSpeed
、
WebPageTest
、
Pingdom
、
PhantomJS
等。
Lighthouse
是 google 一个开源的自动化工具,运行
Lighthouse
的方式有两种:一种是作为 Chrome 扩展程序运行;另一种作为命令行工具运行。Chrome 扩展程序提供了一个对用户更友好的界面,方便读取报告。通过命令行工具可以将 Lighthouse 集成到持续集成系统。
-
无侵入性。 -
简单快捷。缺点: -
不是真实的用户访问情况,只是模拟的。 -
没法考虑到登录的情况,对于需要登录的页面就无法监控到。
真实用户监控
FrontJs
、
oneapm
、
Datadog
等。
-
是真实用户访问情况。 -
可以观察历史性能趋势。 -
有一些额外的功能:报表推送、监控告警等等。缺点: -
有侵入性,会一定程度上响应 web 性能。
performance 分析
基本属性
基本方法
performance
实体对象,通过
getEntriesByName
和
getEntriesByType
方法可对所有的
performance
实体对象 进行过滤,返回特定类型的实体。
-
performance.getEntriesByName() -
performance.getEntriesByType() -
performance.mark() -
performance.clearMarks() -
performance.measure() -
performance.clearMeasures() -
performance.now() ...
提供的 API
performance.getEntriesByType("navigation");
-
重定向次数:performance.navigation.redirectCount -
重定向耗时: redirectEnd - redirectStart -
DNS 解析耗时: domainLookupEnd - domainLookupStart -
TCP 连接耗时: connectEnd - connectStart -
SSL 安全连接耗时: connectEnd - secureConnectionStart -
网络请求耗时 (TTFB): responseStart - requestStart -
数据传输耗时: responseEnd - responseStart -
DOM 解析耗时: domInteractive - responseEnd -
资源加载耗时: loadEventStart - domContentLoadedEventEnd -
首包时间: responseStart - domainLookupStart -
白屏时间: responseEnd - fetchStart -
首次可交互时间: domInteractive - fetchStart -
DOM Ready 时间: domContentLoadEventEnd - fetchStart -
页面完全加载时间: loadEventStart - fetchStart -
http 头部大小:transferSize - encodedBodySize
performance.getEntriesByType("resource");
// 某类资源的加载时间,可测量图片、js、css、XHR
resourceListEntries.forEach(resource => {
if (resource.initiatorType == 'img') {
console.info(`Time taken to load ${resource.name}: `, resource.responseEnd - resource.startTime);
}
});
总结
let p = window.performance.getEntries();
performance.navigation.redirectCount
p.filter(ele => ele.initiatorType === "script").length
p.filter(ele => ele.initiatorType === "css").length
p.filter(ele => ele.initiatorType === "xmlhttprequest").length
p.filter(ele => ele.initiatorType === "img").length
window.performance.getEntriesByType("resource").length
-
重定向耗时: redirectEnd - redirectStart -
DNS 解析耗时: domainLookupEnd - domainLookupStart -
TCP 连接耗时: connectEnd - connectStart -
SSL 安全连接耗时: connectEnd - secureConnectionStart -
网络请求耗时 (TTFB): responseStart - requestStart -
HTML 下载耗时:responseEnd - responseStart -
DOM 解析耗时: domInteractive - responseEnd -
资源加载耗时: loadEventStart - domContentLoadedEventEnd
-
白屏时间: domLoading - fetchStart -
粗略首屏时间: loadEventEnd - fetchStart 或者 domInteractive - fetchStart -
DOM Ready 时间: domContentLoadEventEnd - fetchStart -
页面完全加载时间: loadEventStart - fetchStart
const p = window.performance.getEntries();
let cssR = p.filter(ele => ele.initiatorType === "script");
Math.max(...cssR.map((ele) => ele.responseEnd)) - Math.min(...cssR.map((ele) => ele.startTime));
const p = window.performance.getEntries();
let cssR = p.filter(ele => ele.initiatorType === "css");
Math.max(...cssR.map((ele) => ele.responseEnd)) - Math.min(...cssR.map((ele) => ele.startTime));
如何监控?
-
保证数据的准确性 -
尽量不影响应用的性能
1.基本性能上报
performance navagation timing
中的所有点都上报,其余的上报内容可参考 performance 分析一节中截取部分上报。例如:白屏时间,JS 和 CSS 总数,以及加载总时长。
2.首屏时间计算
performance.getEntries()
拿到的所有图片实体对象,根据图片的初始加载时间和加载完成时间去更新首屏渲染时间。
MutationObserver
接口提供了监视对 DOM 树所做更改的能力,是 DOM3 Events 规范的一部分。
3.异常上报
-
1)js error 监听 window.onerror 事件 -
2)promise reject 的异常 监听 unhandledrejection 事件
window.addEventListener("unhandledrejection", function (event) {
console.warn("WARNING: Unhandled promise rejection. Shame on you! Reason: "
+ event.reason);
});
-
3)资源加载失败 window.addEventListener('error') -
4)网络请求失败 重写 window.XMLHttpRequest 和 window.fetch 捕获请求错误 -
5)iframe 异常 window.frames[0].onerror -
6)window.console.error
4.CGI 上报
前天有一篇文章【困扰99%前端程序员的Vue问题,全在这了(含代码)】,我们忘记了留下作者的名字,该文章系掘金作者“愣锤”2018年所作,在此给愣锤大神比心。
你“在看”我吗?