
Web Performance提供了可以通过的函数(performance 属性提供)测试当前网页或者 web应用的性能,获取更为精确的原始数据,以毫秒为单位。一般放在window.onload事件中读取各种数据,有些值必须在页面完全加载之后才能得出。
API详解
=====
navigationStart 表示从上一个文档卸载结束时的unix时间戳,如果没有上一个文档,这个值将和fetchStart 相等。
为什么使用Image对象.gif文件上报
上报数据封装
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');我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。