页面性能计算和各参数的含义

668 阅读3分钟

确认自己需要关注的指标

常见的指标有:

  1. 页面总加载时间 load

    通过window.addEventLister('load')

  2. 首屏时间

    用户第一次介入页面(白屏)-> 开始渲染 -> 第一屏渲染完毕

  3. 白屏时间

    用户第一次进入页面(白屏)->页面上第一个元素出现

    业界比较关注的通用指标一般是页面总加载时间和白屏时间

各个属性所代表的含义(Window.performance)

  1. connectStart, connectEnd

    分别代表TCP建立连接和连接成功的时间节点。如果浏览器没有进行TCP连接(比如使用持久化连接webscoket),则两者都等于domainLookupEnd;

  2. domComplete

    Html文档完全解析完毕的时间节点;

  3. domContentLoadedEventEnd

    代表DOMContentLoaded事件触发的时间节点:页面文档完全加载并解析完毕之后,会触发DOMContentLoaded事件,HTML文档不会等待样式文件,图片文件,子框架页面的加载(load事件可以用来检测HTML页面是否完全加载完毕(fully-loaded))。

  4. domContentLoadedEventStart

    代表DOMContentLoaded事件完成的时间节点,此刻用户可以对页面进行操作,也就是jQuery中的domready时间;

  5. domInteractive

    代表浏览器解析html文档的状态为interactive时的时间节点。domInteractive并非DOMReady,它早于DOMReady触发,代表html文档解析完毕(即dom tree创建完成)但是内嵌资源(比如外链css、js等)还未加载的时间点;

  6. domLoading

    代表浏览器开始解析html文档的时间节点。我们知道IE浏览器下的document有readyState属性,domLoading的值就等于readyState改变为loading的时间节点;

  7. domainLookupStart domainLookupEnd

    分别代表DNS查询的开始和结束时间节点。如果浏览器没有进行DNS查询(比如使用了cache),则两者的值都等于fetchStart;

  8. fetchStart

    是指在浏览器发起任何请求之前的时间值。在fetchStart和domainLookupStart之间,浏览器会检查当前文档的缓存;

  9. loadEventStart, loadEventEnd

    分别代表onload事件触发和结束的时间节点

  10. navigationStart

  11. redirectStart, redirectEnd 如果页面是由redirect而来,则redirectStart和redirectEnd分别代表redirect开始和结束的时间节点;

  12. requestStart 代表浏览器发起请求的时间节点,请求的方式可以是请求服务器、缓存、本地资源等;

  13. responseStart, responseEnd 分别代表浏览器收到从服务器端(或缓存、本地资源)响应回的第一个字节和最后一个字节数据的时刻;

  14. ecureConnectionStart 可选。如果页面使用HTTPS,它的值是安全连接握手之前的时刻。如果该属性不可用,则返回undefined。如果该属性可用,但没有使用HTTPS,则返回0;

  15. unloadEventStart, unloadEventEnd 如果前一个文档和请求的文档是同一个域的,则unloadEventStart和unloadEventEnd分别代表浏览器unload前一个文档的开始和结束时间节点。否则两者都等于0

import { VueRouter } from 'vue-router/types/router';
import { BaseTrack } from './track';

export class Performance {
    // TODO 注意上报的单位 现在是毫秒
    public static readonly timing = window.performance && window.performance.timing;

    public static init() {
        if (!this.timing) {
            console.warn('当前浏览器不支持performance API');
            return;
        }

        window.addEventListener('load', () => {
            BaseTrack.track(this.getTimings());
        });
    }

    public static record(router?: VueRouter) {
        const setFPT = () => {
            if (window.performance && window.performance.now) {
                this.customFPT = window.performance.now();
            }
        };
        return {
            created: () => {
                if (router) {
                    router.onReady(() => {
                        setFPT();
                    });
                } else {
                    setFPT();
                }
            },
        };
    }


    public static getTimings(): { [key in string]: number } {
        if (!this.timing) {
            console.warn('当前浏览器不支持performance API');
            return {};
        }

        return {
            redirect: this.getRedirectTime(),
            dns: this.getDnsTime(),
            tcp: this.getTcpTime(),
            ttfb: this.getTimeOfFirstByte(),
            req: this.getReqTime(),
            ppdt: this.getParsePureDomTime(),
            dclt: this.getDomContentLoadTime(),
            fpt: this.getFirstPaintTime(),
            load: this.getLoadTime(),
        };
    }

    private static customFPT: number = 0;

    private static getRedirectTime() {
        // 重定向耗时
        return Performance.timing.redirectEnd - Performance.timing.redirectStart;
    }

    private static getDnsTime() {
        // dns查询耗时
        return Performance.timing.domainLookupEnd - Performance.timing.domainLookupStart;
    }

    private static getTcpTime() {
        // tcp连接耗时
        return Performance.timing.connectEnd - Performance.timing.connectStart;
    }

    private static getTimeOfFirstByte() {
        // 读取页面第一个字节耗时
        return Performance.timing.responseStart - Performance.timing.navigationStart;
    }

    private static getReqTime() {
        // request请求耗时
        return Performance.timing.responseEnd - Performance.timing.responseStart;
    }

    private static getParsePureDomTime() {
        // 解析纯DOM树耗时, 不包含js css等资源的加载和执行
        return Performance.timing.domInteractive - Performance.timing.domLoading;
    }

    private static getDomContentLoadTime() {
        // 页面资源加载耗时, 包含vue, js css等资源的加载和执行
        return Performance.timing.domComplete - Performance.timing.domInteractive;
    }

    private static getFirstPaintTime() {
        // first paint time, 首次渲染时间, 即白屏时间
        return Math.round(
            (window.performance.getEntriesByName &&
                window.performance.getEntriesByName('first-paint') &&
                window.performance.getEntriesByName('first-paint')[0] &&
                window.performance.getEntriesByName('first-paint')[0].startTime) ||
                this.customFPT,
        );
    }

    private static getLoadTime() {
        // 页面load总耗时
        return Performance.timing.loadEventStart - Performance.timing.navigationStart;
    }

    private static toSeconds(time: number) {}
}