想要搭建一个前端的性能监控平台,首先要从认识监控指标开始,在浏览器控制台中输入window.performance.timing
(html5的属性)就可以获取到了,而window.performance
也为我们提供了丰富的指标,帮助我们计算我们监控所需要的内容。下面这张图就是网页在各个阶段可以读取到的时间戳:
/1.png)
下面我们来一一解释各个字段的意义:(斜体为不常用的属性)
字段名 | 意义 |
---|---|
navigationStart | 当前浏览器窗口的前一个网页关闭,发生unload事件时的Unix毫秒时间戳。如果没有前一个网页,则等于fetchStart属性。 |
unloadEventStart | 如果前一个网页与当前网页属于同一个域名,则返回前一个网页的unload事件发生时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。 |
unloadEventEnd | 如果前一个网页与当前网页属于同一个域名,则返回前一个网页unload事件的回调函数结束时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。 |
redirectStart | 返回第一个HTTP跳转开始时的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。 |
redirectEnd | 返回最后一个HTTP跳转结束时(即跳转回应的最后一个字节接受完成时)的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。 |
fetchStart | 返回浏览器准备使用HTTP请求读取文档时的Unix毫秒时间戳。该事件在网页查询本地缓存之前发生。 |
domainLookupStart | 返回域名查询开始时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。 |
domainLookupEnd | 返回域名查询结束时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。 |
connectStart | 返回HTTP请求开始向服务器发送时的Unix毫秒时间戳。如果使用持久连接(persistent connection),则返回值等同于fetchStart属性的值。 |
connectEnd | 返回浏览器与服务器之间的连接建立时的对Unix毫秒时间戳,如果建立的连接是持久的,则返回值等同于fetchStart的值。连接建立指的是所有握手和认证过程全部结束 |
secureConnectionStart | 返回浏览器与服务器开始安全链接的握手时的Unix毫秒时间戳。如果当前网页不要求安全链接,则返回0 |
requestStart | 返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的Unix毫秒时间戳 |
reponseStart | 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的Unix毫秒时间戳 |
responseEnd | 返回浏览器从服务器收到(或从本地缓存读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的Unix毫秒时间戳。 |
domLoading | 返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的readystatechange事件触发时)的Unix毫秒时间戳。 |
domInteractive | 返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的Unix毫秒时间戳。 |
domContentLoadedEventStart | 返回当前网页DOMContentLoaded事件发生时(即DOM结构解析完毕、所有脚本开始运行时)的Unix毫秒时间戳。 |
domContentLoadedEventEnd | 返回当前网页所有需要执行的脚本执行完成时的Unix毫秒时间戳。 |
domComplete | 返回当前网页DOM结构生成时(即Document.readyState属性变为“complete”,以及相应的readystatechange事件发生时)的Unix毫秒时间戳。 |
loadEventStart | 返回当前网页load事件的回调函数开始时的Unix毫秒时间戳。如果该事件还没有发生,返回0。 |
loadEventStart | 返回当前网页load事件的回调函数运行结束时的Unix毫秒时间戳。如果该事件还没有发生,返回0。通过while循环持续判断直到loadEventEnd>0则表示完全加载完毕了,此时网络不再有任何数据请求、dom也渲染完毕了 |
这么多的属性,看起来真的很费眼,不过如果你看到了这里,说明你还是对怎么监控很感兴趣的,不管做啥都要有耐心嘛
接下来我们就来开始说说人话——我们到底该监控哪些指标。
对于前端开发人员而言,最关键的在于四个指标:白屏时间、DOM树构建时间、页面加载时间和首屏时间,简单介绍一下这四位好汉:
白屏时间(wit):指的是浏览器开始显示内容的时间,对于现代浏览器而言,页面内容的展示不会等待DOM树(body标签的解析)和CSS树(所有的css文件下载和解析)完全完成再开始渲染,而是马上开始显示中间结果。这也就是我们在弱网环境下看到的,页面先显示文字再加载样式,或者页面从上到下进行渲染的效果。
鉴于上述特性,我们可以通过
responseStart - navigationStart
来近似的获得白屏时间,也即:页面接收到请求返回结果时间 - 页面准备开始请求的时间(或前一个网页卸载的时间)DOM树构建时间(domt):指的是浏览器从html文档中构建DOM树的时间,最初大家都是用onLoad中获取DOM树构建的时间,但是由于这个函数只有在页面所有资源都加载完成之后才会触发,一旦有一个资源被阻塞了,我们就无法获取到正确的时间了(这个方法可以在jquery中使用
$dom.ready(function(){})
来使用)。由此,DomReady事件便诞生了,它在DOM树加载之后立即执行。我们可以通过监听这个事件来获取时间戳:1
2
3document.onreadystatechange = func () {
console.log(+new Date())
};注意:这个函数仅仅是文档被加载并完成解析了,但是图像、样式表和框架之类的子资源仍然在加载中。
当然,做到这一步需要对原生代码进行注入,意味着你需要app端或者pc端的开发人员帮你将这段代码放在业务代码中。如果你嫌麻烦,也可以采用performance的指标来获取:
domComplete - domLoading
,也即:页面DOM结构生成的时间 - 页面的DOM结构开始解析的时间首屏时间(firstt):指的是用户看到的第一屏,也就是当前视窗大小的页面内容完全加载完成,例如iPhone X的屏幕尺寸为 375 * 812,而我的页面总长度为1314px,那么从页面顶部开始的812px就是我首先会展示给用户的区域,也即首屏。
首屏加载时间是直接影响用户体验的
(Tips:在国内的网络条件下,通常一个网站,如果“首屏时间”在2秒以内是比较优秀的,5秒以内用户可以接受,10秒以上就不可容忍了)
页面加载时间(loadt):指的是页面完成整个加载后结束的时间,指页面完成整个加载过程的时刻。从Navigation Timing API上采集,就是loadEventEnd减去navigationStart。