Articles icon indicating copy to clipboard operation
Articles copied to clipboard

前端性能监控 Performance

Open pfan123 opened this issue 3 years ago • 3 comments

Performance 接口可以获取到当前页面中与性能相关的信息。它是 High Resolution Time API 的一部分,同时也融合了 Performance Timeline API、Navigation Timing APIUser Timing APIResource Timing API

该类型的对象可以通过调用只读属性 Window.performance 来获得。

// 兼容性写法
const performance = window.performance || window.msPerformance || window.webkitPerformance;

也可以通过**Performance**获取 Web Worker 执行性能。

performance

Performance 属性

  • Performance.navigation - PerformanceNavigation 对象提供了在指定的时间段里发生的操作相关信息,包括页面是加载还是刷新、发生了多少次重定向等等。Not available in workers.

  • Performance.timing - PerformanceTiming 对象包含延迟相关的性能信息。Not available in workers.

    Navigation Timing Level 2 草案中,已经废弃了 PerformanceTiming 接口,并且提供了新的接口 PerformanceNavigationTiming 代替其功能,performance.getEntriesByType("navigation") 获取。

  • performance.memory - 其是 Chrome 添加的一个非标准扩展,这个属性提供了一个可以获取到基本内存使用情况的对象。不应该使用这个非标准的 API。

    • jsHeapSizeLimit

      上下文内可用堆的最大体积,以字节计算。

    • totalJSHeapSize

      已分配的堆体积,以字节计算。

    • usedJSHeapSize

      当前 JS 堆活跃段(segment)的体积,以字节计算。

  • Performance.timeOrigin - 返回性能测量开始时的时间的高精度时间戳。

Performance 方法

  • Performance.clearMarks() - 将给定的 mark 从浏览器的性能输入缓冲区中移除。
  • Performance.clearMeasures() - 将给定的 measure 从浏览器的性能输入缓冲区中移除。
  • Performance.clearResourceTimings() - 从浏览器的性能数据缓冲区中移除所有 entryType 是 "resource" 的 performance entries
  • Performance.getEntries() - 基于给定的 filter 返回一个 PerformanceEntry 对象的列表。
  • Performance.getEntriesByName() - 基于给定的 nameentry type 返回一个 PerformanceEntry 对象的列表。
  • Performance.getEntriesByType() - 基于给定的 entry type 返回一个 PerformanceEntry 对象的列表
  • Performance.mark() - 根据给出 name 值,在浏览器的性能输入缓冲区中创建一个相关的timestamp
  • Performance.measure() - 在浏览器的指定 start mark 和 end mark 间的性能输入缓冲区中创建一个指定的 timestamp
  • Performance.now() - 返回一个表示从性能测量时刻开始经过的毫秒数 DOMHighResTimeStamp
  • Performance.setResourceTimingBufferSize() - 将浏览器的资源 timing 缓冲区的大小设置为 "resource" type performance entry 对象的指定数量
  • Performance.toJSON()- 其是一个 JSON 格式转化器,返回 Performance 对象的 JSON 对象

performance.navigation 对象

除了时间信息,performance还可以提供一些用户行为信息,主要都存放在 performance.navigation 对象上面。

它有两个属性:

(1)performance.navigation.type

该属性返回一个整数值,表示网页的加载来源,可能有以下4种情况:

  • 0:网页通过点击链接、地址栏输入、表单提交、脚本操作等方式加载,相当于常数performance.navigation.TYPE_NAVIGATENEXT。

  • 1:网页通过“重新加载”按钮或者location.reload()方法加载,相当于常数performance.navigation.TYPE_RELOAD。

  • 2:网页通过“前进”或“后退”按钮加载,相当于常数performance.navigation.TYPE_BACK_FORWARD。

  • 255:任何其他来源的加载,相当于常数performance.navigation.TYPE_UNDEFINED。

(2)performance.navigation.redirectCount

该属性表示当前网页经过了多少次重定向跳转。

performance.timing 对象

performance 对象的 timing 属性指向一个对象,它包含了各种与浏览器性能有关的时间数据,提供浏览器处理网页各个阶段的耗时。比如,performance.timing.navigationStart 就是浏览器处理当前网页的启动时间。

img

performance.timing 对象包含以下属性(全部为只读):

  • 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毫秒时间戳。
  • responseStart:返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的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。
  • loadEventEnd:返回当前网页load事件的回调函数运行结束时的Unix毫秒时间戳。如果该事件还没有发生,返回0。

计算性能指标

  • DNS查询耗时 = domainLookupEnd - domainLookupStart
  • TCP链接耗时 = connectEnd - connectStart
  • request请求耗时 = responseEnd - responseStart
  • 解析dom树耗时 = domComplete - domInteractive
  • domready时间 = domContentLoadedEventEnd - fetchStart
  • 首屏渲染时间、首次有内容渲染时间 performance.getEntriesByType('paint') https://w3c.github.io/paint-timing/
  • onload时间 = loadEventEnd - fetchStart
// 计算加载时间
function getPerformanceTiming () {  
    const performance = window.performance || window.msPerformance || window.webkitPerformance;
 
    if (!performance) {
        // 当前浏览器不支持
        console.log('你的浏览器不支持 performance 接口');
        return;
    }
 
    const t = performance.timing;
    const times = {};
 
    //【重要】页面加载完成的时间
    //【原因】这几乎代表了用户等待页面可用的时间
    times.loadPage = t.loadEventEnd - t.navigationStart;
 
    //【重要】解析 DOM 树结构的时间
    //【原因】反省下你的 DOM 树嵌套是不是太多了!
    times.domReady = t.domComplete - t.responseEnd;
 
    //【重要】重定向的时间
    //【原因】拒绝重定向!比如,http://example.com/ 就不该写成 http://example.com
    times.redirect = t.redirectEnd - t.redirectStart;
 
    //【重要】DNS 查询时间
    //【原因】DNS 预加载做了么?页面内是不是使用了太多不同的域名导致域名查询的时间太长?
    // 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)            
    times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
 
    //【重要】读取页面第一个字节的时间
    //【原因】这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加CDN 处理了么?加带宽了么?加 CPU 运算速度了么?
    // TTFB 即 Time To First Byte 的意思
    // 维基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
    times.ttfb = t.responseStart - t.navigationStart;
 
    //【重要】内容加载完成的时间
    //【原因】页面内容经过 gzip 压缩了么,静态资源 css/js 等压缩了么?
    times.request = t.responseEnd - t.requestStart;
 
    //【重要】执行 onload 回调函数的时间
    //【原因】是否太多不必要的操作都放到 onload 回调函数里执行了,考虑过延迟加载、按需加载的策略么?
    times.loadEvent = t.loadEventEnd - t.loadEventStart;
 
    // DNS 缓存时间
    times.appcache = t.domainLookupStart - t.fetchStart;
 
    // 卸载页面的时间
    times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;
 
    // TCP 建立连接完成握手的时间
    times.connect = t.connectEnd - t.connectStart;
 
    return times;
}

performance.mark()

mark 方法用于为相应的视点做标记。

window.performance.mark('mark_fully_loaded');

clearMarks 方法用于清除标记,如果不加参数,就表示清除所有标记。

window.peformance.clearMarks('mark_fully_loaded');

window.performance.clearMarks();

performance.getEntries()

浏览器获取网页时,会对网页中每一个对象(脚本文件、样式表、图片文件等等)发出一个HTTP请求。performance.getEntries方法以数组形式,返回这些请求的时间统计信息,有多少个请求,返回数组就会有多少个成员。

由于该方法与浏览器处理网页的过程相关,所以只能在浏览器中使用。

window.performance.getEntries()[0]

// PerformanceResourceTiming { 
//   responseEnd: 4121.6200000017125, 
//   responseStart: 4120.0690000005125, 
//   requestStart: 3315.355000002455, 
//   ...
// }

上面代码返回第一个 HTTP请求(即网页的HTML源码)的时间统计信息。该信息以一个高精度时间戳的对象形式返回,每个属性的单位是毫秒(milliseconds)。

性能监测对象

PerformanceObserver 用于监测性能度量事件,在浏览器的性能时间轴记录下一个新的 performance entries 的时候将会被通知 。

此特性在 Web Worker 中可用。

// 测量 Long Task
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // TODO...
    console.log(entry);
  }
});

observer.observe({entryTypes: ['longtask']});

Other Resources

Performance

Navigation Timing Level 2

改善页面性能 - 开发者需要了解的 Performance API 标准

PerformanceNavigationTiming.loadEventEnd

初探 performance – 监控网页与程序性能

评估关键渲染路径

Performance API

pfan123 avatar Apr 01 '21 07:04 pfan123

performance timing 准备要废弃了,用什么api替代呢

huoguozhang avatar Dec 07 '21 12:12 huoguozhang

performance timing 准备要废弃了,用什么api替代呢

好问题,现在 chrome 还是支持的,到底啥时候废弃,替代品又是啥呢?

reng99 avatar Apr 21 '22 03:04 reng99

performance timing 准备要废弃了,用什么api替代呢 @huoguozhang @reng99

performance.getEntriesByType('navigation')

iShawnWang avatar Jun 18 '22 14:06 iShawnWang