window.performance(前端性能监控并进行上报)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了window.performance(前端性能监控并进行上报)相关的知识,希望对你有一定的参考价值。

Web Performance提供了可以通过的函数(performance 属性提供)测试当前网页或者 web应用的性能,获取更为精确的原始数据,以毫秒为单位。一般放在window.onload事件中读取各种数据,有些值必须在页面完全加载之后才能得出。

图示

window.performance(前端性能监控并进行上报)_前端监控

API详解

navigationStart 表示从上一个文档卸载结束时的unix时间戳,如果没有上一个文档,这个值将和fetchStart 相等。

  • redirectStart, redirectEnd 如果页面是由redirect而来,则redirectStart和redirectEnd分别代表redirect开始和结束的时间节点。跳转且是同域名内部的重定向才算,否则值为0。 fetchStart:浏览器准
  • fetchStart 浏览器发起任何请求之前的时间值,发生在检查本地缓存之前,在fetchStart和domainLookupStart之间,浏览器会检查当前文档的缓存
  • domainLookupStart domainLookupEnd 分别代表DNS查询的开始和结束时间节点。如果浏览器没有进行DNS查询(比如使用cache),则都等于fetchStart
  • connectStart、connectEnd 分别代表TCP建立连接和连接成功的时间节点。如果浏览器没有进行TCP连接(比如持久化连接webscoket),则两者都等于domainLookupEnd
  • secureConnectionStart 可选。如果页面使用HTTPS,它的值是安全连接握手之前的时刻。如果该属性不可用,则返回undefined。如果该属性可用,但没有使用HTTPS,则返回0。该api位于connectStart、connectEnd之间。
  • requestStart 代表浏览器发起请求的时间节点,请求的方式可以是服务器,缓存,本地资源。
  • responseStart, responseEnd 分别代表浏览器收到从服务器端(或缓存、本地资源)响应回的第一个字节和最后一个字节数据的时刻; -domLoading 代表浏览器开始解析html文档的时间节点。我们知道IE浏览器下的document有readyState属性,domLoading的值就等于readyState改变为loading的时间节点
  • domInteractive 代表浏览器解析html文档的状态为interactive时的事件节点,即完成解析DOM树的时间,Document.readyState变为interactive,并将抛出readystatechange相关事件。此时只是DOM树解析完成,这时候并没有开始加载网页内的资源(外链css、js)。
  • domContentLoadEventStart 代表domContentLoaded事件触发的时间节点:页面文档完全加载并解析完成之后,会触发DOMContentLoaded,Html文档不会等待样式文件,图片文件,自框架页面的加载(load事件可用来检测页面是否完全加载完毕)
  • domContentLoadEventEnd 代表domContentLoaded事件完成的时间节点,此时用户可以对页面进行操作
  • domComplete Html文档完全解析完成的时间节点

为什么使用Image对象.gif文件上报

  • 防止跨域 只要能上报数据,无论是请求GIF文件还是请求其他普通文件(JS)或者是请求接口,服务器端其实并不关心具体的上报方式。 但是图片的src属性并不会跨域,并且同样可以发起请求
  • 防止阻塞页面加载,影响用户体验 通常,创建资源节点后只有将对象注入到浏览器DOM树后,浏览器才会实际发送资源请求。反复操作DOM不仅会引发性能问题,而且载入js/css资源还会阻塞页面渲染,影响用户体验。 但是图片请求例外。构造图片打点不仅不用插入DOM,只要在js中new出Image对象就能发起请求,而且还没有阻塞问题,在没有js的浏览器环境中也能通过img标签正常打点,这是其他类型的资源请求所做不到的
  • 相比PNG/JPG,GIF的体积最小 最小的BMP文件需要74个字节,PNG需要67个字节,而合法的GIF,只需要43个字节。同样的响应,GIF可以比BMP节约41%的流量,比PNG节约35%的流量

上报数据封装

performance.js

/* eslint-disable no-console */
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, 首次渲染时间, 即白屏时间
// getEntriesByName 浏览器兼容性不好,故有时需要自己去定义
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)

上报

track.ts

/* eslint-disable no-console */
import queryString from query-string;
import v4 as uuid from uuid;

let image: HTMLImageElement | null;

export class BaseTrack

public static track(params: [key: string]: any )
try
// if (process.env.NODE_ENV !== production)
// // 非生产环境不上报
// return;
//
//封装上报数据参数
const qs = queryString.stringify(
timestamp: Date.now(),
traceId: this.getTraceId(),
url: location.href,
...params,
);
//上报
this.reportByImg(qs);
catch (e)
console.error(e);



private static serverUrl: string =
https://open-demo-qiuku.cn-beijing.log.aliyuncs.com/logstores/qiuku-demo/track_ua.gif?APIVersion=0.6.0&;

private static reportByImg(qs: string, retryTimes: number = 3)
const retry = () =>
image = null;
retryTimes && this.reportByImg(qs, retryTimes - 1);
;
return new Promise((resolve) =>
try
image = new Image();
image.src = this.serverUrl + qs;
//请求失败,再次请求,默认请求失败后请求最多三次
image.onerror = () =>
retry();
;
catch (e)
console.error(e);

);

//获取追踪Id,标记是哪个用户
private static getTraceId()
try
const traceKey = qiuku_track_id;
let traceId = localStorage.getItem(traceKey);
if (!traceId)
traceId = uuid();
localStorage.setItem(traceKey, traceId!);

return traceId;
catch (e)
return ;


main.ts

// import @babel/polyfill;

import Vue from vue;
import App from ./App.vue;
import ./registerServiceWorker;
import router from ./router;
import Performance from ../src/utils/performance;
Vue.config.productionTip = false;

//初始化
Performance.init();
//自定义分析dom渲染的时间
Vue.directive(analysis,
inserted(el, options)
console.log(`$options.value = $Date.now() - window.performance.timing.navigationStart`);

);
new Vue(
router,
render: (h) => h(App),
mixins: [Performance.record(router)],
).$mount(#app);

以上是关于window.performance(前端性能监控并进行上报)的主要内容,如果未能解决你的问题,请参考以下文章

前端性能监控-window.performance.timing篇

window.performance(前端性能监控并进行上报)

前端性能监控

使用performance进行网页性能监控

Nodejs中分析web前端性能(window.performance)

skywalking-client-js前端监控实现分析(零基础搞懂前端监控)