一、属性的分解

feedcb786acd68f73b140cf6d838f02.png
memor:对内存的占用
navigation:网页导航相关数据
1、redirectCount:重定向的数量(只读),这个接口有同源策略限制,即仅能检测同源的重定向;
2、type:返回0,1,2
0:TYPE_NAVIGATE(用户通过常规导航方式访问页面,列如点一个链接、或者一般get方式)
1:TYPE_RELOAD(用户通过刷新,包括通过js调运接口方式访问页面)
2:TYPE_BACK_FORWARD (用户通过后退按钮访问本页面)

timing 整体结构如下
33872196-d6c35844-df50-11e7-8bcc-1fdcac66ce64.png

  • navigationStart:部分浏览器实现为startTime。代表浏览器开始unload前一个页面文档的开始时间节点,比如我们正在浏览器访问baidu.com ,在地址栏输入google.com地址并回车,浏览器的执行动作依次为:unload当前文档(即baidu.com)->请求下一文档(即google.com)navigationStart的值便是触发unload当前文档的时间节点;
  • redirectStart 和 redirectEnd:如果页面是由重定向(redirect)而来,则redirectStart 和 redirectEnd分别代表redirect开始和结束的时间节点;
  • unloadEventStart 和 unloadEventEnd:如果前一个文档和请求的文档是同一个域,则unloadEventStart 和 unloadEventEnd分别代表浏览器unload前一个文档的开始和结束时间节点。负责两者都为0;
  • fetchStart:指浏览器发起任何请求值的时间值。在fetchStart 和 domainLookupStart之间,浏览器会检查当前文档的缓存;
  • domainLookupStart 和 domainLookupEnd:分别代表DNS查询的开始和结束时间。如果浏览器没有进行DNS查询(比如使用了cache),则两个值都为fetchStart;
  • connectStart 和 connectEnd:分别代表TCP建立连接和连接成功的时间节点。如果浏览器没有进行TCP连接(比如使用持久化链接websocket),这两个值都为domainLookupEnd;
  • secureConnectionStart:可选。如果页面使用HTTPS,它的值时安全连接握手之前的时刻。如果该属性不可用,则返回undefined。如国该属性可用,但没有使用HTTPS,则返回0;
  • responseStart 和 responseEnd:分别代表浏览器收到服务器端(或缓存、本地资源)响应回的第一个字节和最后一个字节数据的时间;
  • domLoading:代表浏览器开始解析html文档的时间节点。IE浏览器下的document有readyStart属性,domLoading的值就等于readyStart改变为loading的时间节点;
  • domInteractive:代表浏览器解析html文档的状态为interactive时的时间节点。domInteractive并非DOMReady,,它早于DOMReady触发,代表htm文档解析完毕(dom tree创建完成)但是内嵌资源(外链css、js)还未加载的时间点
  • domContentLoadedEventStart:代表DOMContentLoaded事件触发时间节点;
  • domContentLoadedEventEnd:代表DOMContentLoaded事件完成的时间节点,此时用户可以对页面操作了
  • domComplete:html文档完全解析完毕的时间节点
  • loadEventStart 和 loadEventEnd:分别代表onload事件触发和结束的时间节点;
  • 检测网络带宽 navigator.connection.downlink * 1024 /8 // KB/s

使用该api时需要在页面完全加载完成之后才能使用,最简单的办法是在window.onload事件中读取各种数据,因为很多值必须在页面完全加载之后才能得出**

需要再页面onload之后才能获取到的时间节点
domInteractive
**
domContentLoadedEventEnd
** loadEventEnd
loadEventStart
performance.getEntries()
**

二、计算性能指标

performance.timing
1、区间阶段耗时
DNS 解析耗时 = domainLookupEnd - domainLookupStart
TCP 链接耗时 = connectEnd - connectStart
SSL 安全连接耗时 = **connectEnd- **secureConnectionStart
TTFB 网络请求耗时 = responseStart- requestStart
数据传输耗时 = responseEnd- responseStart
DOM 解析耗时 = domInteractive- responseEnd (**需在onload之后)
资源加载耗时 =
loadEventStart- domContentLoadedEventEnd **(需在onload之后)
2、关键性能指标
首包时间 =
responseStart- domainLookupStart** 白屏时间 = responseEnd- fetchStart
首次可交互时间 =
domInteractive- fetchStart (需在onload之后)
HTML加载完成时间 =
domContentLoadedEventEnd- fetchStart (需在onload之后)
页面完全加载时间 =
loadEventEnd- fetchStart **(需在onload之后)

performance.getEntries()
返回所有静态资源信息(如下图),返回类型为数组。initiatorType为资源类型,durtaion为请求时间

625e76211030ddfcf86bbad6f233dfc.png

  1. // 标记一个开始点
  2. const performance = window.performance;
  3. const navigator = window.navigator;
  4. // 操作系统
  5. const os = navigator.userAgent.split("(")[1].split(";")[0];
  6. const navigationType = ["导航方式", "刷新", "后退按钮"];
  7. // 根据名称生成高精度时间戳(打点)
  8. performance.mark("loading-start");
  9. // 以下时间节点以及性能计算不需要在onload时获取
  10. const {
  11. domainLookupStart,
  12. // 请求连接被发送到网络时的时间戳
  13. connectStart,
  14. // 网络建立的时间节点
  15. connectEnd,
  16. secureConnectionStart,
  17. responseEnd,
  18. responseStart,
  19. requestStart,
  20. fetchStart,
  21. domainLookupEnd,
  22. // 加载页面的起始时间
  23. navigationStart,
  24. domComplete,
  25. redirectStart,
  26. redirectEnd,
  27. } = performance.timing;
  28. const {
  29. // 返回地理定位信息
  30. geolocation,
  31. // 是否连接互联网,true未断网
  32. onLine,
  33. // 所在平台,返回win32
  34. platform,
  35. // 网络情况
  36. connection,
  37. } = navigator;
  38. const {
  39. totalJSHeapSize,
  40. usedJSHeapSize
  41. } = performance.memory;
  42. let info = {
  43. // 内存占用情况
  44. memory: performance.memory,
  45. // 重定向耗时
  46. Redirect: redirectEnd - redirectStart,
  47. // DNS查找耗时
  48. DNSLookup: domainLookupEnd - domainLookupStart,
  49. // SSL 安全连接耗时
  50. ssl: connectEnd - secureConnectionStart,
  51. // TCP链接耗时
  52. TCPLink: connectEnd - connectStart,
  53. // Time to First Byte(TTFB)
  54. // 网络请求耗时 TTFB 有多种计算方式,ARMS 以 Google Development 定义为准
  55. ttfb: responseStart - requestStart,
  56. // 数据传输耗时
  57. HTTPResponse: responseEnd - responseStart,
  58. // 白屏耗时
  59. WhiteScreen: responseStart - navigationStart,
  60. // 2.关键性能指标
  61. // 首包时间
  62. Firstbyte: responseStart - domainLookupStart,
  63. // First Paint Time, 首次渲染时间 / 白屏时间
  64. FPT: responseEnd - fetchStart,
  65. //页面的来源信息
  66. navigation: performance.navigation,
  67. // 表示网页的加载来源,
  68. type: navigationType[performance.navigation.type] || "其他来源",
  69. // http请求抓取文档之时的时间戳
  70. fetchStart,
  71. // 如果大于0,表示有可能出现了内存泄漏
  72. JSHeapSize: usedJSHeapSize - totalJSHeapSize, // 使用过的堆栈内存 - js堆栈内存总大小
  73. os,
  74. geolocation,
  75. onLine,
  76. platform,
  77. connection
  78. };
  79. window.onload = function () {
  80. // 以下时间节点以及性能计算需要在onload时获取
  81. const {
  82. domInteractive,
  83. domContentLoadedEventEnd,
  84. loadEventEnd,
  85. loadEventStart,
  86. } = performance.timing;
  87. // console.log(loadEventEnd , fetchStart) 这里loadEventEnd获取一直为0,待解决
  88. let info = {
  89. // dom树解析耗时
  90. DOMParse: domInteractive - responseEnd,
  91. // HTML 加载完成时间, 即 DOM Ready 耗时
  92. DOMready: domContentLoadedEventEnd - fetchStart,
  93. // 资源加载耗时
  94. res: loadEventStart - domContentLoadedEventEnd,
  95. // onload耗时
  96. // Loaded: loadEventEnd - fetchStart,这里loadEventEnd获取一直为0,待解决
  97. // Time to Interact,首次可交互时间
  98. TTI: domInteractive - fetchStart,
  99. // 资源测速
  100. duration: performance.getEntries(),
  101. };
  102. let time = 0;
  103. let result = [];
  104. let duration = info.duration;
  105. if (duration) {
  106. duration.map((item) => {
  107. result.push({
  108. '资源名称': item.name,
  109. '资源类型': item.entryType,
  110. '谁发起的请求': item.initiatorType,
  111. '加载时间': item.duration
  112. });
  113. if (item.entryType == "resource") {
  114. // 加载静态资源总耗时
  115. time += item.duration;
  116. }
  117. });
  118. console.table(result);
  119. console.log("加载静态资源总耗时", time);
  120. } else {
  121. console.log("不支持");
  122. }
  123. // 标记一个结束点
  124. performance.mark("loading-end");
  125. // 标记指定开始点和结束点之间的时间戳(连线)
  126. performance.measure(
  127. "loading",
  128. "loading-start",
  129. "loading-end"
  130. );
  131. // 获取所有名称为loading的measures
  132. var measures = performance.getEntriesByName("loading");
  133. var measure = measures[0];
  134. console.log("loading time:", measure.duration);
  135. console.log(info)
  136. // 获取之后清除标记
  137. performance.clearMarks();
  138. performance.clearMeasures();
  139. };
  140. // 获取IP地址
  141. function getIPs(callback) {
  142. // var ip_dups = {};
  143. //兼容firefox chrome
  144. var RTCPeerConnection = window.RTCPeerConnection ||
  145. window.mozRTCPeerConnection ||
  146. window.webkitRTCPeerConnection;
  147. if (!RTCPeerConnection) {
  148. var iframe = document.createElement('iframe');
  149. iframe.sandbox = 'allow-same-origin';
  150. iframe.style.display = 'none';
  151. document.body.appendChild(iframe);
  152. var win = iframe.contentWindow;
  153. window.RTCPeerConnection = win.RTCPeerConnection;
  154. window.mozRTCPeerConnection = win.mozRTCPeerConnection;
  155. window.webkitRTCPeerConnection = win.webkitRTCPeerConnection;
  156. RTCPeerConnection = window.RTCPeerConnection ||
  157. window.mozRTCPeerConnection ||
  158. window.webkitRTCPeerConnection;
  159. }
  160. let pc = new RTCPeerConnection({
  161. iceServers: [{
  162. urls: "stun:stun.services.mozilla.com"
  163. }]
  164. });
  165. let noop = () => {};
  166. let localIPs = {};
  167. let ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g;
  168. let iterateIP = (ip) => {
  169. if (!localIPs[ip]) callback(ip);
  170. localIPs[ip] = true;
  171. };
  172. pc.createDataChannel('');
  173. pc.createOffer().then((sdp) => {
  174. sdp.sdp.split('\n').forEach(function (line) {
  175. if (line.indexOf('candidate') < 0) return;
  176. line.match(ipRegex).forEach(iterateIP);
  177. });
  178. pc.setLocalDescription(sdp, noop, noop);
  179. }).catch((reason) => {
  180. console.log(reason);
  181. });
  182. pc.onicecandidate = (ice) => {
  183. if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;
  184. ice.candidate.candidate.match(ipRegex).forEach(iterateIP);
  185. };
  186. }
  187. getIPs((ip) => {
  188. console.log(ip);
  189. });