小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
Vue 全局配置 API
根据2.x官方说明,在开发模式中配置:
Vue.config.performance = true;
// 或 Vue.config.performance = process.env.NODE_ENV !== 'production';
同时配合浏览器(ps:支持 performance.mark API的)开发者工具,可获取组件相关性能信息。
perf.js
这个全局配置的实现,看看2.x源码 src\core\util\perf.js 的具体写法:
利用了Performance API的一些方法,如下perf.measure等
// src\core\util\perf.js
import { inBrowser } from './env'
export let mark
export let measure
if (process.env.NODE_ENV !== 'production') {
// 判断是否支持performance
const perf = inBrowser && window.performance
/* istanbul ignore if */
if (
perf &&
perf.mark &&
perf.measure &&
perf.clearMarks &&
perf.clearMeasures
) {
// 用于标记需获取性能信息的节点
mark = tag => perf.mark(tag)
// 根据标记测量性能信息,后清除标记
measure = (name, startTag, endTag) => {
perf.measure(name, startTag, endTag)
perf.clearMarks(startTag)
perf.clearMarks(endTag)
// perf.clearMeasures(name)
}
}
}
对其引用
// src\platforms\web\entry-runtime-with-compiler.js
import { mark, measure } from '../util/perf'
// 标记compile已结束,接着根据开始与结束标记定义一个性能信息测量
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
其余引用可见:
- src\core\instance\init.js
- src\core\instance\lifecycle.js
Performance API
根据上述可知Performance能够获取到当前页面中的性能相关信息,是个丰富的API
暂列举一些常用的属性&方法,其余详见传送门
属性
Performance.timing
对象,包含了当前页面与性能相关的信息,输出可见:
关于该对象各属性说明:PerformanceTiming
利用某些属性可进行常用计算:如 DNS查询耗时:domainLookupEnd - domainLookupStart等,见Performance — 前端性能监控利器
方法
Performance.mark(name)
根据name值,在浏览器的性能缓冲区创建一个时间戳
Performance.clearMarks(name)
name参数可选,若存在则根据值对应移除创建的时间戳,反之移除性能缓存区的所有时间戳标记
Performance.measure(name, startMark, endMark)
利用Performance.mark进行开始标记和结束标记,定义一次性能测量,命名为name值
performance.getEntriesByName(name,type)
根据测量名称name获取测量数据,返回一个给定名称和name和type属性的性能信息对象数组
Performance.clearMeasures(name)
同Performance.clearMarks,name也是可选,移除对应的某个测量或所有测量实体数据
Performance.now()
返回一个精确到毫秒的时间戳,可用于简易计算某代码段的执行时间
const start = window.performance.now();
// ……
const end = window.performance.now();
console.log(`执行了${end-start}ms`)
自定义封装
借鉴前端性能监控window.performance的巧妙写法一文
避免performance.timing某些属性,如loadEventEnd值在onload触发后仍然为0,利用setInterval进行如下封装:
import Vue from "vue";
const isServer = Vue.prototype.$isServer;
export default {
methods: {
// 获取页面性能数据
getPerformanceInfo() {
if (isServer) return;
let perf = window.performance || window.webkitPerformance;
if (!perf) return;
let t = perf.timing;
let info = {};
// 设置定时器的作用:避免performance.timing.loadEventEnd为0
let timer = setInterval(() => {
if (t.loadEventEnd !== 0) {
clearInterval(timer);
// eg:DNS查询耗时
info.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
// 其他计算
// ……
}
}, 100);
return info;
},
// 进行时间戳标记
perfMark(tag) {
if (isServer) return;
performance.mark(`${tag}`); // 添加标记名称,用于后续计算时间差
},
// 定义测量,名称的默认值action,后移除声明的时间戳和测量
perfMeasure(startTag, endTag, name = "action") {
if (isServer) return;
performance.measure(`${name}`, `${startTag}`, `${endTag}`);
let measures = performance.getEntriesByName(`${name}`);
this.perfClear(name, startTag, endTag);
return measures[0];
},
// 清除信息
perfClear(name, ...tags) {
// 移除指定声明的时间戳标记
tags.forEach(item => {
performance.clearMarks(`${item}`);
});
// 移除指定声明的测量
if (name) performance.clearMeasures(`${name}`);
},
// 获取时间戳标记信息
toGetPerformanceMark(name) {
return performance.getEntries({name : name, entryType: "mark"}).filter(item=>item.name===name);
}
}
};
封装后使用:
import Performance from "./performance";
export default {
// ……
mixins: [Performance],
data() {
return {
perfInfo: {}
}
},
mounted() {
let timing = this.getPerformanceInfo();
// 设置定时器,确保数据返回
let timer = setInterval(() => {
if (Object.keys(timing).length) {
clearInterval(timer);
this.perfInfo = Object.assign({}, this.perfInfo, timing);
}
}, 100);
}
// ……
// perfMark、perfMeasure的使用,仅属于简单的封装,暂不列举,具体可参考MDN Web Docs的demo
}
注意事项
MDN Web Docs中,对于 Performance.timing 提及:
已废弃: 该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。
Last but not least
如有不妥,请多指教~