pfan123 / Articles

经验文章
169 stars 25 forks source link

前端性能监控 Performance #87

Open pfan123 opened 3 years ago

pfan123 commented 3 years ago

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 方法

performance.navigation 对象

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

它有两个属性:

(1)performance.navigation.type

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

(2)performance.navigation.redirectCount

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

performance.timing 对象

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

img

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

计算性能指标

// 计算加载时间
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

huoguozhang commented 2 years ago

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

reng99 commented 2 years ago

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

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

iShawnWang commented 2 years ago

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

performance.getEntriesByType('navigation')