UNPKG

hiper-weimai

Version:

🚀 A statistical analysis tool for performance testing

210 lines (199 loc) 9.96 kB
const Util = require('../util') /** * https://developer.mozilla.org/zh-CN/docs/Web/API/Document/readyState * https://stackoverflow.com/questions/13346746/document-readystate-on-domcontentloaded * readyState = interactive,可以近似地作为DOM Ready事件 * readyState = complete,可以近似地作为load事件 * DOM Ready事件在「interactive」和「complete」之间执行 * readyState的值解释: * loading 文档仍在加载 * interactive 文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载 * complete 文档和所有子资源已经全部加载完毕。loads事件即将出发。 */ class Analyzer { constructor (data) { this.data = data } /** * @param {Number} domainLookupStart 返回用户代理对当前文档所属域进行DNS查询开始的时间。 * 如果此请求没有DNS查询过程,如长连接,资源cache,甚至是本地资源等。 那么就返回 fetchStart的值 * @param {Number} domainLookupEnd 返回用户代理对结束对当前文档所属域进行DNS查询的时间。 * 如果此请求没有DNS查询过程,如长连接,资源cache,甚至是本地资源等。那么就返回 fetchStart的值 * @returns {Number} DNS查询耗时 */ getDNSTime (domainLookupStart, domainLookupEnd) { return domainLookupEnd - domainLookupStart } /** * @param {Number} connectStart 返回用户代理向服务器服务器请求文档,开始建立连接的那个时间, * 如果此连接是一个长连接,又或者直接从缓存中获取资源(即没有与服务器建立连接)。 * 则返回domainLookupEnd的值 * @param {Number} connectEnd 返回用户代理向服务器服务器请求文档, * 建立连接成功后的那个时间,如果此连接是一个长连接,又或者直接从缓存中获取资源(即没有与服务器建立连接)。 * 则返回domainLookupEnd的值 * @returns {Number} TCP链接耗时 */ getTCPTime (connectStart, connectEnd) { return connectEnd - connectStart } /** * @param {Number} responseStart 返回用户代理从服务器、缓存、本地资源中,接收到第一个字节数据的时间 * @param {Number} responseEnd 返回用户代理接收到最后一个字符的时间,和当前连接被关闭的时间中,更早的那个。 * 同样,文档可能来自服务器、缓存、或本地资源 * @returns {Number} 网页本身的下载耗时 */ getDownloadTime (responseStart, responseEnd) { return responseEnd - responseStart } /** * * @param {Number} domInteractive 准备加载新页面的起始时间 * @param {Number} domComplete readyState = complete的时候 * @returns {Number} 解析DOM Tree耗时 * 这个说法有点儿不严谨,这个只能当做dom加载完毕以后,子资源的下载耗时,名字起的容易让人误解 */ getAfterDOMReadyTheDownloadTimeOfTheRes (domInteractive, domComplete) { return domComplete - domInteractive } /** * * @param {Number} navigationStart 准备加载新页面的起始时间 * @param {Number} responseStart 返回用户代理从服务器、缓存、本地资源中,接收到第一个字节数据的时间 * @returns {Number} 白屏时间 */ getWhiteScreenTime (navigationStart, responseStart) { return responseStart - navigationStart } /** * * @param {*} domContentLoadedEventStart * @param {*} domContentLoadedEventEnd */ getDOMContentLoadedTime (navigationStart, DOMContentLoadedTime) { return DOMContentLoadedTime - navigationStart } /** * * @param {*} navigationStart * @param {*} domContentLoadedEventEnd */ getDOMReadyTime (navigationStart, domContentLoadedEventEnd) { return domContentLoadedEventEnd - navigationStart } /** * * @param {Number} navigationStart 准备加载新页面的起始时间 * @param {Number} loadEventEnd 文档触发load事件结束后的时间。如果load事件没有触发,那么该接口就返回0 * @returns {Number} DOM Ready耗时 */ getLoadTime (navigationStart, loadEventEnd) { return loadEventEnd - navigationStart } getAverage (total, length) { return total / length } /** * * @param {Number} requestStart * @param {Number} responseStart * @return {Number} TTFB * TTFB (Time To First Byte),是最初的网络请求被发起到从服务器接收到第一个字节这段时间, * 它包含了 TCP连接时间,发送HTTP请求时间和获得响应消息第一个字节的时间。 - 上面是百度百科的解释 * 但是在chrome上,只包含刚开始发送request到接收到第一个byte的时间, * 发送request前面的预操作则不算在内 */ getTTFB (requestStart, responseStart) { return responseStart - requestStart } statistics (data = this.data) { if (!data) { return } if (!Array.isArray(data)) { data = [ data ] } let length = data.length // 分析次数 // DNS查询耗时 let totalDNSTime = 0 // TCP链接耗时 let totalTCPTime = 0 // TTFB let totalTTFBTime = 0 // donwload资源耗时 let totalDownloadTime = 0 // 解析dom树耗时 let totalAfterDOMReadyTheDownloadTimeOfTheRes = 0 // 白屏时间 let totalWhiteScreenTime = 0 // DOMContentLoaded时间 let totalDOMContentLoadedTime = 0 // domready时间 let totalDOMReadyTime = 0 // onload时间 let totalLoadTime = 0 // 首屏时间 let totalFirstScreenTime = 0 for (let item of data) { let { pageData, entries, firstScreenTime, DOMContentLoadedTime } = item let { navigationStart, domainLookupStart, domainLookupEnd, connectStart, connectEnd, requestStart, responseStart, responseEnd, // domLoading, domInteractive, domContentLoadedEventStart, domContentLoadedEventEnd, domComplete, // loadEventStart, loadEventEnd, } = pageData.timing totalDNSTime += this.getDNSTime(domainLookupStart, domainLookupEnd) totalTCPTime += this.getTCPTime(connectStart, connectEnd) totalTTFBTime += this.getTTFB(requestStart, responseStart) totalDownloadTime += this.getDownloadTime(responseStart, responseEnd) totalAfterDOMReadyTheDownloadTimeOfTheRes += this.getAfterDOMReadyTheDownloadTimeOfTheRes(domInteractive, domComplete) totalWhiteScreenTime += this.getWhiteScreenTime(navigationStart, responseStart) totalDOMContentLoadedTime += this.getDOMContentLoadedTime(navigationStart, DOMContentLoadedTime) totalDOMReadyTime += this.getDOMReadyTime(navigationStart, domContentLoadedEventEnd) totalLoadTime += this.getLoadTime(navigationStart, loadEventEnd) totalFirstScreenTime += firstScreenTime } // console.log('DNS lookup time:', Util.formatMSToHumanReadable(this.getAverage(totalDNSTime, length))) // console.log('TCP connect time:', Util.formatMSToHumanReadable(this.getAverage(totalTCPTime, length))) // console.log('TTFB:', Util.formatMSToHumanReadable(this.getAverage(totalTTFBTime, length))) // console.log('Download time of the page:', Util.formatMSToHumanReadable(this.getAverage(totalDownloadTime, length))) // console.log('After DOM Ready the download time of resources:', Util.formatMSToHumanReadable(this.getAverage(totalAfterDOMReadyTheDownloadTimeOfTheRes, length))) // console.log('White screen time:', Util.formatMSToHumanReadable(this.getAverage(totalWhiteScreenTime, length))) // console.log('DOM Ready time:', Util.formatMSToHumanReadable(this.getAverage(totalDOMReadyTime, length))) // console.log('Load time:', Util.formatMSToHumanReadable(this.getAverage(totalLoadTime, length))) // console.log('DNS查询耗时:', Util.formatMSToHumanReadable(this.getAverage(totalDNSTime, length))) // console.log('TCP连接耗时:', Util.formatMSToHumanReadable(this.getAverage(totalTCPTime, length))) // console.log('TTFB:', Util.formatMSToHumanReadable(this.getAverage(totalTTFBTime, length))) // console.log('页面下载耗时:', Util.formatMSToHumanReadable(this.getAverage(totalDownloadTime, length))) // console.log('白屏时间:', Util.formatMSToHumanReadable(this.getAverage(totalWhiteScreenTime, length))) // console.log('DOM Ready耗时:', Util.formatMSToHumanReadable(this.getAverage(totalDOMReadyTime, length))) // console.log('DOM Ready之后继续进行资源下载的耗时:', Util.formatMSToHumanReadable(this.getAverage(totalAfterDOMReadyTheDownloadTimeOfTheRes, length))) // console.log('Load时间:', Util.formatMSToHumanReadable(this.getAverage(totalLoadTime, length))) // console.log(`\n`) return { pageData: { dnsTime: Util.formatMSToHumanReadable(this.getAverage(totalDNSTime, length)), tcpTime: Util.formatMSToHumanReadable(this.getAverage(totalTCPTime, length)), TTFB: Util.formatMSToHumanReadable(this.getAverage(totalTTFBTime, length)), pageDownloadTime: Util.formatMSToHumanReadable(this.getAverage(totalDownloadTime, length)), whiteScreenTime: Util.formatMSToHumanReadable(this.getAverage(totalWhiteScreenTime, length)), DOMContentLoadedTime: Util.formatMSToHumanReadable(this.getAverage(totalDOMContentLoadedTime, length)), DOMReadyTime: Util.formatMSToHumanReadable(this.getAverage(totalDOMReadyTime, length)), afterDOMReadyDownloadTime: Util.formatMSToHumanReadable(this.getAverage(totalAfterDOMReadyTheDownloadTimeOfTheRes, length)), loadTime: Util.formatMSToHumanReadable(this.getAverage(totalLoadTime, length)), firstScreenTime: Util.formatMSToHumanReadable(this.getAverage(totalFirstScreenTime, length)) } } } } module.exports = Analyzer