本文首发于知乎 《10分钟完全搞懂前端页面性能监控》,搬运转载请注明出处,不然追究版权责任。
前端页面性能是一个很是核心的用户体验指标。本文介绍阿里UC 岳鹰全景监控平台 如何设计一个通用、低侵入性、自动上报的页面性能监控方案。主要采用的是Navigation Timing API以及sendBeacon等方法。前端
一个页面性能差的话会大大影响用户体验。用户打开页面等待的过久,可能会直接关掉页面,甚至就再也不使用了,这种状况在移动端更加明显,移动端用户对页面响应延迟容忍度很低。vue
虽然页面性能很重要,可是在实际使用中,页面性能差的状况并很多见。首先,在产品的迭代演进过程当中,页面性能可能会被忽略,性能随着版本迭代而有所衰减;其次,性能优化是一项复杂而挑战的事情,须要明确的优化方向和具体的优化手段才能快速落地取效。react
因此咱们须要一个性能监控系统,持续监控和预警页面性能的情况,而且在发现瓶颈的时候指导优化工做。web
为了帮助开发者更好地衡量和改进前端页面性能,W3C性能小组引入了 Navigation Timing API ,实现了自动、精准的页面性能打点;开发者能够经过 window.performance
属性获取。后端
performance.timing
接口(定义了从 navigationStart
至 loadEventEnd
的 21 个只读属性)performance.navigation
(定义了当前文档的导航信息,好比是重载仍是向前向后等)下图是W3C初版的 Navigation Timing 的处理模型。从当前浏览器窗口卸载旧页面开始,到新页面加载完成,整个过程一共被切分为 9 个小块:提示卸载旧文档、重定向/卸载、应用缓存、DNS 解析、TCP 握手、HTTP 请求处理、HTTP 响应处理、DOM 处理、文档装载完成。每一个小块的首尾、中间作事件分界,取 Unix 时间戳,两两事件之间计算时间差,从而获取中间过程的耗时(精确到毫秒级别)。api
上图是 Level 1 的规范,2012 年末进入候选建议阶段,至今仍在平常使用中;可是在W3C的议程上,它已经功成身退,让位给了精度更高,功能更强大,层次更分明的 Level 2(处理模型以下图)。好比独立划分出来的 Resource Timing,使得咱们能够获取具体资源的详细耗时信息。跨域
使用上面的指标,咱们能够计算许多重要的指标,如首字节的时间,页面加载时间,dns查找以及链接是否安全。咱们把 Navigation Timing API 提供的指标作下归类,按照从上到下的时间流,右边的时刻标记了每一个指标从哪里开始计算到哪里截止,好比,跳转时间 redirect 由 redirectEnd - redirectStart
计算获得,其余的类推。浏览器
页面性能统计的起始点时间,应该是用户输入网址回车后开始等待的时间。一个是经过navigationStart
获取,至关于在URL输入栏回车或者页面按F5刷新的时间点;另一个是经过 fetchStart
,至关于浏览器准备好使用 HTTP 请求获取文档的时间。缓存
从开发者实际分析使用的场景,浏览器重定向、卸载页面的耗时对页面加载分析并没有太大做用;一般建议使用 fetchStart
做为统计起始点。安全
主文档返回第一个字节的时间,是页面加载性能比较重要的指标。对用户来讲通常无感知,对于开发者来讲,则表明访问网络后端的总体响应耗时。
用户看到页面展现出现一个元素的时间。不少人认为白屏时间是页面返回的首字节时间,但这样其实并不精确,由于头部资源还没加载完毕,页面也是白屏。
相对来讲具有「白屏时间」统计意义的指标,能够取 domLoading - fetchStart
,此时页面开始解析DOM树,页面渲染的第一个元素也会很快出现。
从W3C Navigation Timing Level 2 的方案设计,能够直接采用 domInteractive - fetchStart
,此时页面资源加载完成,即将进入渲染环节。
首屏时间是指页面第一屏全部资源完整展现的时间。这是一个对用户来讲很是直接的体验指标,可是对于前端倒是一个很是难以统计衡量的指标。
具有必定意义上的指标可使用,domContentLoadedEventEnd - fetchStart
,甚至使用loadEventStart - fetchStart
,此时页面DOM树已经解析完成而且显示内容。
如下给出统计页面性能指标的方法。
let times = {}; let t = window.performance.timing; // 优先使用 navigation v2 https://www.w3.org/TR/navigation-timing-2/ if (typeof win.PerformanceNavigationTiming === 'function') { try { var nt2Timing = performance.getEntriesByType('navigation')[0] if (nt2Timing) { t = nt2Timing } } catch (err) { } } //重定向时间 times.redirectTime = t.redirectEnd - t.redirectStart; //dns查询耗时 times.dnsTime = t.domainLookupEnd - t.domainLookupStart; //TTFB 读取页面第一个字节的时间 times.ttfbTime = t.responseStart - t.navigationStart; //DNS 缓存时间 times.appcacheTime = t.domainLookupStart - t.fetchStart; //卸载页面的时间 times.unloadTime = t.unloadEventEnd - t.unloadEventStart; //tcp链接耗时 times.tcpTime = t.connectEnd - t.connectStart; //request请求耗时 times.reqTime = t.responseEnd - t.responseStart; //解析dom树耗时 times.analysisTime = t.domComplete - t.domInteractive; //白屏时间 times.blankTime = (t.domInteractive || t.domLoading) - t.fetchStart; //domReadyTime times.domReadyTime = t.domContentLoadedEventEnd - t.fetchStart;
Navigation Timing API能够监控大部分前端页面的性能。但随着SPA模式的盛行,相似vue,reactjs等框架的普及,页面内容渲染的时机被改变了,W3C标准没法彻底知足原来的监控意义。
幸运的是,目前W3C关于首屏统计已经进入了提议阶段,以Chrome为首的浏览器正在打造更能表明用户使用体验的FP、FCP、FMP指标,而且逐步开放API。
测量好时间后,就须要将数据发送给服务端。页面性能统计数据对丢失率要求比较低,且性能统计应该在尽可能不影响主流程的逻辑和页面性能的前提下进行。
var i = new Image(); i.onload = i.onerror = i.onabort = function () { i = i.onload = i.onerror = i.onabort = null; } i.src = url;
大部分现代浏览器都支持 navigator.sendBeacon方法。这个方法能够用来发送一些统计和诊断的小量数据,特别适合上报统计的场景。
window.addEventListener('unload', logData, false); function logData() { navigator.sendBeacon("/log", analyticsData); }
当浏览器支持sendBeacon方法,优先使用该方法,使用img方式降级上报。
navigation-timing-2 https://www.w3.org/TR/navigation-timing-2/
Navigation API指南 https://s0developer0mozilla0org.icopy.site/en-US/docs/Web/Performance/Navigation_and_resource_timings
以用户为中心的性能指标 https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics?hl=zh-cn
页面性能对业务指标的影响 https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/