从历史上看,咱们对客户端性能监控形式十分无限,而且还遇到了API浏览器的限度,妨碍了咱们精确地掂量客户端性能。

侥幸的是,因为有了新的面向性能的api,这种状况正在开始扭转。当初,浏览器的Performance API给咱们提供了精确度量Web页面性能的工具。

不耐烦看的同学能够间接调到开端应用办法一览

应用 Performance API 的益处

  • 这些api减少了在开发工具中使用性能剖析时的教训;
  • Chrome开发工具和其余工具,如Lighthouse只在开发阶段有帮忙。然而应用Performance API,咱们能够在生产中取得实在的用户度量数据(RUM - real user measurement);
  • 咱们能够失去十分准确的工夫戳数据,这使得这些性能指标的剖析十分精确。
Performance 接口能够获取到以后页面中与性能相干的信息。它是 High Resolution Time API 的一部分,同时也交融了 Performance Timeline API、Navigation Timing API、 User Timing API 和 Resource Timing API。
—— MDN

High resolution time

高分辨率工夫的准确水平可达几分之一毫秒。相比之下,基于Date的工夫只能准确到毫秒。这种精确度使它成为精确测量工夫的现实工具。

由User-Agent (UA)测量的高分辨率工夫不会随着零碎工夫的任何更改而更改,因为它是从UA创立的全局时钟中获取的。

在Performance API中测量的每个测量值都是高分辨率工夫。这就是为什么你总是听到性能API是高分辨率工夫API的一部分。

Performance timeline API

Performance timeline API 是Performance API的扩大。该扩大提供了基于特定筛选条件检索性能指标的接口。

Performance Timeline API提供了以下三个办法,蕴含在性能接口中:

  • getEntries()
  • getEntriesByName()
  • getEntriesByType()

每个办法返回从Performance API的所有其余扩大收集的entries列表。

PerformanceObserver 是API中蕴含的另一个接口。它次要用于察看性能时间轴(Performance Timeline),并在浏览器记录时告诉新的性能条目。它能够用来度量浏览器和 Node.js 应用程序中某些性能指标。

Performance entries

咱们用Performance API度量的货色称为entries。以下是可供咱们应用的性能项:

  • mark
  • measure
  • navigation
  • resource
  • paint
  • frame

应用这些条目和各自的API来度量性能。

应用 Navigation timing API 和 Resource timing API测量

navigation timing API 和 resource timing API 有许多内容重叠,你能够浏览此文章具体理解他们之间的差别。

获取办法:

// Navigation Timing entries:const navigationEntries = performance.getEntriesByType("navigation")[0];// 内容{  "name": "https://awebsite.com",  "entryType": "navigation",  "startTime": 0,  "duration": 7816.495000151917,  "initiatorType": "navigation",  "nextHopProtocol": "",  "workerStart": 9.504999965429306,  "redirectStart": 0,  "redirectEnd": 0,  "fetchStart": 39.72000000067055,  "domainLookupStart": 39.72000000067055,  "domainLookupEnd": 39.72000000067055,  "connectStart": 39.72000000067055,  "connectEnd": 39.72000000067055,  "secureConnectionStart": 0,  "requestStart": 39.72000000067055,  "responseStart": 6608.200000133365,  "responseEnd": 6640.834999969229,  "transferSize": 0,  "encodedBodySize": 0,  "decodedBodySize": 0,  "serverTiming": [],  "unloadEventStart": 0,  "unloadEventEnd": 0,  "domInteractive": 6812.060000142083,  "domContentLoadedEventStart": 6812.115000095218,  "domContentLoadedEventEnd": 6813.680000137538,  "domComplete": 7727.995000081137,  "loadEventStart": 7760.385000146925,  "loadEventEnd": 7816.495000151917,  "type": "navigate",  "redirectCount": 0}
// Resource Timing entriesconst resourceListEntries = performance.getEntriesByType("resource");

这将返回一个资源计时对象数组。单个对象看起来是这样的,可用于获取某一Web资源的前后体现信息:

{  "name": "https://awebsite.com/images/image.png",  "entryType": "resource",  "startTime": 237.85999999381602,  "duration": 11.274999938905239,  "initiatorType": "img",  "nextHopProtocol": "h2",  "workerStart": 0,  "redirectStart": 0,  "redirectEnd": 0,  "fetchStart": 237.85999999381602,  "domainLookupStart": 237.85999999381602,  "domainLookupEnd": 237.85999999381602,  "connectStart": 237.85999999381602,  "connectEnd": 237.85999999381602,  "secureConnectionStart": 0,  "requestStart": 243.38999995961785,  "responseStart": 244.40500000491738,  "responseEnd": 249.13499993272126,  "transferSize": 0,  "encodedBodySize": 29009,  "decodedBodySize": 29009,  "serverTiming": []}

应用场景一览

// DNS解析const dnsTime = navigationEntries.domainLookupEnd - navigationEntries.domainLookupStart;// 响应 + 响应工夫const totalTime = navigationEntries.responseEnd - navigationEntries.requestStart;// 缓存查找响应工夫const fetchTime = navigationEntries.responseEnd - navigationEntries.fetchStart;// 应用Service worker响应工夫let workerTime = 0;if (navigationEntries.workerStart > 0) {workerTime = navigationEntries.responseEnd - navigationEntries.workerStart;}// 收到第一个字节const ttfb = navigationEntries.responseStart - navigationEntries.requestStart;// 重定向工夫const redirectTime = navigationEntries.redirectEnd - navigationEntries.redirectStart;// 测量HTTP报头大小const headerSize = navigationEntries.transferSize - navigationEntries.encodedBodySize;// 测量资源加载工夫resourceListEntries.forEach(resource => {  if (resource.initiatorType == 'img') {    console.info(`Time taken to load ${resource.name}: `, resource.responseEnd - resource.startTime);  }});// 获取单个资源指标const impResourceTime = performance.getEntriesByName("https://awebsite.com/imp-resource.png");

补充:间接应用 performance.timing 计算

正告: 该属性在 Navigation Timing Level 2 specification 中曾经被废除,请应用 PerformanceNavigationTiming 代替。尽管一些浏览器依然反对它,但兴许只是正筹备移除或出于兼容性而保留。

const timingInfo = window.performance.timing;// DNS解析,DNS查问耗时timingInfo.domainLookupEnd - timingInfo.domainLookupStart;// TCP连贯耗时timingInfo.connectEnd - timingInfo.connectStart;// 取得首字节消耗工夫,也叫TTFBtimingInfo.responseStart - timingInfo.navigationStart;// domReady工夫(与DomContentLoad事件对应)timingInfo.domContentLoadedEventStart - timingInfo.navigationStart;// DOM资源下载timingInfo.responseEnd - timingInfo.responseStart;// 筹备新页面工夫耗时timingInfo.fetchStart - timingInfo.navigationStart;// 重定向耗时timingInfo.redirectEnd - timingInfo.redirectStart;// Appcache 耗时timingInfo.domainLookupStart - timingInfo.fetchStart;// unload 前文档耗时timingInfo.unloadEventEnd - timingInfo.unloadEventStart;// request申请耗时timingInfo.responseEnd - timingInfo.requestStart;// 申请结束至DOM加载timingInfo.domInteractive - timingInfo.responseEnd;// 解释dom树耗时timingInfo.domComplete - timingInfo.domInteractive;// 从开始至load总耗时timingInfo.loadEventEnd - timingInfo.navigationStart;// 白屏工夫timingInfo.responseStart - timingInfo.fetchStart;// 首屏工夫timingInfo.domComplete - timingInfo.fetchStart;

参考:

Using the Performance API

How to practically use Performance API to measure performance

Performance.timing