前端监控数据收集(perf)

196 阅读6分钟

这节我们了解一下获取用户访问网页速度和Web应用程序的性能,那如何来获取这些数据呢?我们项目中使用PerformanceTiming 接口来获取当前页面中与时间相关的信息。PerformanceTiming 可以通过只读属性Performance.timing 获得实现该接口的一个对象。

我们先来看一张图,timing API的提供了整个请求的各个阶段的时间信息

1956469674-5c8f961dcc2a1_fix732 (1).png

PerformanceTiming.navigationStart

  • 是一个无符号long long 型的毫秒数,表征了从同一个浏览器上下文的上一个文档卸载(unload)结束时的UNIX时间戳。如果没有上一个文档,这个值会和PerformanceTiming.fetchStart相同。

PerformanceTiming.unloadEventStart

  • 是一个无符号long long 型的毫秒数,表征了unload事件抛出时的UNIX时间戳。如果没有上一个文档,or if the previous document, or one of the needed redirects, is not of the same origin, 这个值会返回0.

PerformanceTiming.unloadEventEnd

  • 是一个无符号long long 型的毫秒数,表征了unload事件处理完成时的UNIX时间戳。如果没有上一个文档,or if the previous document, or one of the needed redirects, is not of the same origin, 这个值会返回0.

PerformanceTiming.redirectStart

  • 是一个无符号long long 型的毫秒数,表征了第一个HTTP重定向开始时的UNIX时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0.

PerformanceTiming.redirectEnd

  • 是一个无符号long long 型的毫秒数,表征了最后一个HTTP重定向完成时(也就是说是HTTP响应的最后一个比特直接被收到的时间)的UNIX时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0.

PerformanceTiming.fetchStart

  • 是一个无符号long long 型的毫秒数,表征了浏览器准备好使用HTTP请求来获取(fetch)文档的UNIX时间戳。这个时间点会在检查任何应用缓存之前。

PerformanceTiming.domainLookupStart

  • 是一个无符号long long 型的毫秒数,表征了域名查询开始的UNIX时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 PerformanceTiming.fetchStart一致。

PerformanceTiming.domainLookupEnd

  • 是一个无符号long long 型的毫秒数,表征了域名查询结束的UNIX时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 PerformanceTiming.fetchStart一致。

PerformanceTiming.connectStart

  • 是一个无符号long long 型的毫秒数,返回HTTP请求开始向服务器发送时的Unix毫秒时间戳。如果使用持久连接(persistent connection),则返回值等同于fetchStart属性的值。

PerformanceTiming.connectEnd

  • 是一个无符号long long 型的毫秒数,返回浏览器与服务器之间的连接建立时的Unix毫秒时间戳。如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。

PerformanceTiming.secureConnectionStart

  • 是一个无符号long long 型的毫秒数,返回浏览器与服务器开始安全链接的握手时的Unix毫秒时间戳。如果当前网页不要求安全连接,则返回0。

PerformanceTiming.requestStart

  • 是一个无符号long long 型的毫秒数,返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的Unix毫秒时间戳。

PerformanceTiming.responseStart

  • 是一个无符号long long 型的毫秒数,返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的Unix毫秒时间戳。如果传输层在开始请求之后失败并且连接被重开,该属性将会被数制成新的请求的相对应的发起时间。

PerformanceTiming.responseEnd

  • 是一个无符号long long 型的毫秒数,返回浏览器从服务器收到(或从本地缓存读取,或从本地资源读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的Unix毫秒时间戳。

PerformanceTiming.domLoading

  • 是一个无符号long long 型的毫秒数,返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的 readystatechange事件触发时)的Unix毫秒时间戳。

PerformanceTiming.domInteractive

  • 是一个无符号long long 型的毫秒数,返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的Unix毫秒时间戳。

PerformanceTiming.domContentLoadedEventStart

  • 是一个无符号long long 型的毫秒数,返回当解析器发送DOMContentLoaded 事件,即所有需要被执行的脚本已经被解析时的Unix毫秒时间戳。

PerformanceTiming.domContentLoadedEventEnd

  • 是一个无符号long long 型的毫秒数,返回当所有需要立即执行的脚本已经被执行(不论执行顺序)时的Unix毫秒时间戳。

PerformanceTiming.domComplete

  • 是一个无符号long long 型的毫秒数,返回当前文档解析完成,即Document.readyState 变为 'complete'且相对应的readystatechange 被触发时的Unix毫秒时间戳。

PerformanceTiming.loadEventStart

  • 是一个无符号long long 型的毫秒数,返回该文档下,load事件被发送时的Unix毫秒时间戳。如果这个事件还未被发送,它的值将会是0。

PerformanceTiming.loadEventEnd

  • 是一个无符号long long 型的毫秒数,返回当load事件结束,即加载事件完成时的Unix毫秒时间戳。如果这个事件还未被发送,或者尚未完成,它的值将会是0.

重点来了!!!看了以上参数,我们想要的数据来源有了,现在要做的便是去整理这些数据,将他变成我们项目中使用的数据。我们将要收集的时间归为两类:

1.区间阶段耗时

DNS 解析耗时

dns: timing.domainLookupEnd - timing.domainLookupStart

TCP 连接耗时

tcp: timing.connectEnd - timing.connectStart

SSL 安全连接耗时

ssl: timing.connectEnd - timing.secureConnectionStart

Time to First Byte(TTFB),网络请求耗时 TTFB 有多种计算方式,ARMS 以 Google Development 定义为准

ttfb: timing.responseStart - timing.requestStart

数据传输耗时

trans: timing.responseEnd - timing.responseStart

DOM 解析耗时

dom: timing.domInteractive - timing.responseEnd

资源加载耗时

res: timing.loadEventStart - timing.domContentLoadedEventEnd

2.关键性能指标

首包时间

firstbyte: timing.responseStart - timing.domainLookupStart

First Paint Time, 首次渲染时间 / 白屏时间

fpt: timing.responseEnd - timing.fetchStart

Time to Interact,首次可交互时间

tti: timing.domInteractive - timing.fetchStart

HTML 加载完成时间, 即 DOM Ready 时间

ready: timing.domContentLoadedEventEnd - timing.fetchStart

页面完全加载时间

load:timing.loadEventEnd - timing.fetchStart

现在这两部分数据有了,我们就可以将这些数据上传到我们后台服务上去了,是不是很简单呢,^_^。对于如何展示我们收集的数据,请前往hubing.online 瞅一眼哦。

不是很明白?那我再附上一些源码吧

    //监听perf
    let performanceTime = function () {
        var timing = performance.timing;
        var loadTime = timing.loadEventEnd - timing.navigationStart;//过早获取时,loadEventEnd有时会是0
        if (loadTime <= 0) {
            // 未加载完,延迟200ms后继续times方法,直到成功
            setTimeout(function () {
                performanceTime();
            }, 200);
            return;
        }
        uploadUserData(1, {
            // 1.区间阶段耗时
            //  DNS 解析耗时 
            dns: formatTime(timing.domainLookupEnd - timing.domainLookupStart),
            // TCP 连接耗时
            tcp: formatTime(timing.connectEnd - timing.connectStart),
            // SSL 安全连接耗时
            ssl: formatTime(timing.connectEnd - timing.secureConnectionStart),
            // Time to First Byte(TTFB),网络请求耗时 TTFB 有多种计算方式,ARMS 以 Google Development 定义为准
            ttfb: formatTime(timing.responseStart - timing.requestStart),
            // 数据传输耗时
            trans: formatTime(timing.responseEnd - timing.responseStart),
            // DOM 解析耗时
            dom: formatTime(timing.domInteractive - timing.responseEnd),
            // 资源加载耗时
            res: formatTime(timing.loadEventStart - timing.domContentLoadedEventEnd),
            // 2.关键性能指标
            // 首包时间
            firstbyte: formatTime(timing.responseStart - timing.domainLookupStart),
            // First Paint Time, 首次渲染时间 / 白屏时间
            fpt: formatTime(timing.responseEnd - timing.fetchStart),
            // Time to Interact,首次可交互时间
            tti: formatTime(timing.domInteractive - timing.fetchStart),
            // HTML 加载完成时间, 即 DOM Ready 时间
            ready: formatTime(timing.domContentLoadedEventEnd - timing.fetchStart),
            // 页面完全加载时间
            load: function () {
                return formatTime(timing.loadEventEnd - timing.fetchStart);
            }(),
            navt: (function () {
                let type = "";
                switch (performance.navigation.type) {
                    case 0:
                        type = 'NAVIGATE';
                        break;
                    case 1:
                        type = 'RELOAD';
                        break;
                    case 2:
                        type = 'BACK_FORWARD';
                        break;
                    case 255:
                        type = 'RESERVED';
                        break;
                }
                return type;
            })()
        });
    }

    window.addEventListener("load", function () {
        performanceTime();
    });

喜欢请点个赞呗

或者去github地址Star一下