前言
在日常的项目开发过程中,开发需要知道项目在客户端运行的性能,包括页面白屏耗时, 完全加载耗时, 解析dom树耗时等等一系列的性能指标,然后根据这些性能指标对项目进行相应的优化。所以可以通过浏览器开发者工具下的performance进行性能监控,performance API是浏览器暴露给js的接口,可以通过这个接口来获取我们所需的性能指标,在浏览器开发者工具输入performance会得到如下图所示:
1、performance.timing的属性介绍
下图是页面加载流程:
接下来看一下
Performanc.timing这个API的对象属性,如下:
| 标题 | 描述 |
|---|---|
| connectStart | 浏览器向服务器请求文档,开始建立连接的时间,如果此连接是一个长连接,或者无需与服务器连接(命中缓存),则返回domainLookupEnd的值 |
| connectEnd | 浏览器向服务器请求文档,建立连接成功的时间 |
| domComplete | 浏览器把document.readyState设置为“complete”的时间点 |
| domContentLoadedEventStart | 文档发生DOMContentLoaded事件的时间 |
| domContentLoadedEventEnd | 文档的DOMContentLoaded事件结束的时间 |
| domInteractive | 浏览器把document.readyState设置为“interactive”的时间点,DOM树创建结束 |
| domLoading | 浏览器把document.readyState设置为“loading”的时间点,开始构建dom树的时间点 |
| domainLookupStart | 返回浏览器开始DNS查询的时间,如果此请求没有DNS查询过程,如长连接、资源cache、甚至是本地资源等,那么就返回fetchStart的值 |
| domainLookupEnd | 返回浏览器结束DNS查询的时间,如果没有DNS查询过程,同上 |
| fetchStart | 发起获取当前文档的时间点,个人理解是浏览器收到发起页面请求的时间点 |
| loadEventStart | 文档触发load事件的时间 |
| loadEventEnd | 文档出发load事件结束时的时间 |
| navigationStart | 从同一个浏览器上下文的上一个文档卸载(unload)结束时的时间 |
| redirectStart | 第一个HTTP重定向开始时的时间 |
| redirectEnd | 最后一个HTTP重定向完成时(也就是说是HTTP响应的最后一个比特直接被收到的时间)的时间 |
| requestStart | 浏览器向服务器发出HTTP请求的时间(注意没有requestEnd) |
| responseStart | 浏览器开始接收第一个字节数据的时间,数据可能来自于服务器、缓存、或本地资源 |
| responseEnd | 浏览器接收最后一个字节数据的时间,或连接被关闭的时间 |
| secureConnectionStart | 浏览器与服务器开始安全链接的握手时的时间 |
| unloadEventStart | 卸载上一个文档开始的时间 |
| unloadEventEnd | 卸载上一个文档结束的时间 |
有了Performance.timing这个API,便可以通过它的属性来计算我们需要的性能指标,比如DNS查询耗时、白屏时间、domready等等,如下
- DNS查询耗时 = domainLookupEnd - domainLookupStart
- TCP链接耗时 = connectEnd - connectStart
- 请求耗时 = responseEnd - requestStart
- 解析dom树耗时 = domComplete - domInteractive
- 白屏时间 = domLoading - navigationStart
- domready时间 = domContentLoadedEventEnd - fetchStart
- onload时间 = loadEventEnd - loadEventStart
- 整个页面加载时间 = loadEventEnd -navigationStart
1.1、计算性能工具类实现
通过上面介绍的性能指标、对象属性来实现工具类: time.js
(function () {
function handleAddListener(type, fn) {
if (window.addEventListener) {
window.addEventListener(type, fn);
} else {
window.attachEvent(`on${type}`, fn);
}
}
function getTiming() {
try {
const time = performance.timing;
var timingObj = {};
const loadTime = (time.loadEventEnd - time.loadEventStart) / 1000;
if (loadTime < 0) {
setTimeout(function () {
getTiming();
}, 200);
return;
}
timingObj['重定向时间'] = (time.redirectEnd - time.redirectStart) / 1000;
timingObj['DNS解析时间'] =
(time.domainLookupEnd - time.domainLookupStart) / 1000;
timingObj['TCP完成握手时间'] =
(time.connectEnd - time.connectStart) / 1000;
timingObj['HTTP请求响应完成时间'] =
(time.responseEnd - time.requestStart) / 1000;
timingObj['DOM开始加载前所花费时间'] =
(time.responseEnd - time.navigationStart) / 1000;
timingObj['DOM加载完成时间'] =
(time.domComplete - time.domLoading) / 1000;
timingObj['DOM结构解析完成时间'] =
(time.domInteractive - time.domLoading) / 1000;
timingObj['脚本加载时间'] =
(time.domContentLoadedEventEnd - time.domContentLoadedEventStart) /
1000;
timingObj['onload事件时间'] =
(time.loadEventEnd - time.loadEventStart) / 1000;
timingObj['**白屏时间**'] = (time.domLoading - time.fetchStart) / 1000;
timingObj['页面完全加载时间'] =
timingObj['重定向时间'] +
timingObj['DNS解析时间'] +
timingObj['TCP完成握手时间'] +
timingObj['HTTP请求响应完成时间'] +
timingObj['DOM结构解析完成时间'] +
timingObj['DOM加载完成时间'];
Object.keys(timingObj).forEach((key) => {
console.log(`${key}:${timingObj[key]}秒(s)`);
});
console.log(performance, performance.timing);
} catch (e) {
console.log(e);
console.log(timingObj);
console.log(performance, performance.timing);
}
}
handleAddListener('load', getTiming);
})();
然后在inde.html的最后引入time.js
然后就可以在我们的开发者工具的控制台监听首页的性能了,如下图:
2、performance.getEntries()
这个API能帮我们获得资源的请求时间,包括JS、CSS、图片等
如上图所示,可以看到这个API请求返回的是一个数组,这个数组包括整个页面所有的资源加载,上图打开了一个其中一个资源,可以看到如下信息:
entryType:类型为resource;name:资源的url;initiatorType:资源是link;- 资源时间:
duration的值,是responseEnd - startTime得到的
3、performance.memory
这个API主要是得到浏览器内存情况
jsHeapSizeLimit:内存大小限制totalJSHeapSize:可使用的内容userdJSHeapSize:已使用的内容
userdJSHeapSize表示所有被使用的JS堆栈内存,totalJSHeapSize可使用的JS堆栈内存,如果userdJSHeapSize的值大于totalJSHeapSize,就可能出现内存泄漏