各位朋友,大家好!我是你们今天的性能优化小能手。今天咱们不聊那些高大上的框架,也不啃那些难懂的算法,咱们就来聊聊一个浏览器自带的小工具,但能量却不小的东西——PerformanceEntry
。
咱们先来个热身:啥是 PerformanceEntry
?
想象一下,你开着一辆跑车(你的网站),想知道这辆车跑得怎么样,光看速度表可不行,还得看看油耗、发动机温度、轮胎磨损等等。PerformanceEntry
就相当于这辆跑车的各种传感器,它记录了你网站运行过程中的各种性能指标。
简单来说,PerformanceEntry
是一个接口,它表示一个性能度量事件。这些事件可以是浏览器内置的,比如页面加载时间、资源加载时间,也可以是你自己定义的,比如某个关键功能的执行时间。
为什么我们需要 PerformanceEntry
?
“知己知彼,百战不殆”,优化网站性能也是一样。你不了解问题出在哪里,怎么可能对症下药呢?PerformanceEntry
就像一个性能体检报告,告诉你网站的优点和缺点,让你能更有效地进行优化。
- 精准定位性能瓶颈: 知道哪里慢了,才能针对性地优化。
- 监控性能趋势: 长期监控性能指标,及时发现潜在问题。
- 自定义性能指标: 衡量特定功能的性能,满足个性化需求。
- 数据驱动优化: 用数据说话,让优化更有说服力。
PerformanceEntry
的家庭成员:各种类型的性能事件
PerformanceEntry
本身只是一个接口,它有很多不同的子类型,分别代表不同的性能事件。我们来认识一下几个常见的家庭成员:
类型(entryType ) |
描述 | 常用属性 |
---|---|---|
navigation |
记录页面导航的性能数据,比如重定向、DNS 查询、TCP 连接、请求响应等等。 | startTime , duration , redirectStart , redirectEnd , fetchStart , domainLookupStart , domainLookupEnd , connectStart , connectEnd , requestStart , responseStart , responseEnd , domInteractive , domContentLoadedEventStart , domContentLoadedEventEnd , loadEventStart , loadEventEnd |
resource |
记录资源(图片、CSS、JS 等)加载的性能数据,比如请求时间、响应时间、传输大小等等。 | startTime , duration , name , initiatorType , transferSize , encodedBodySize , decodedBodySize , fetchStart , domainLookupStart , domainLookupEnd , connectStart , connectEnd , requestStart , responseStart , responseEnd |
paint |
记录首次渲染(First Paint, FP)和首次内容渲染(First Contentful Paint, FCP)的时间。 | startTime , duration , name (可以是 "first-paint" 或 "first-contentful-paint") |
longtask |
记录执行时间超过 50 毫秒的任务,这些任务可能会阻塞主线程,影响用户体验。 | startTime , duration , name (通常为空字符串) |
measure |
记录自定义的性能指标,比如某个函数的执行时间、某个操作的耗时等等。 | startTime , duration , name |
mark |
记录代码中某个特定时间点的时间戳,用于后续计算性能指标。 | startTime , name |
event |
记录事件的性能数据,例如鼠标点击、键盘输入等。 | startTime , duration , name , interactionId |
如何获取 PerformanceEntry
?
获取 PerformanceEntry
主要有两种方式:
performance.getEntries()
: 返回一个包含所有已记录的PerformanceEntry
对象的数组。 你可以使用performance.getEntriesByType(entryType)
或者performance.getEntriesByName(name, entryType)
来过滤特定类型的或者特定名称的entry。PerformanceObserver
: 创建一个观察者对象,它可以监听新的PerformanceEntry
对象被创建。 这种方法可以实时的获取性能数据。
代码实战:获取页面加载时间
咱们先来个简单的例子,获取页面的完整加载时间(从开始导航到 load
事件触发):
window.addEventListener('load', () => {
const navigationEntries = performance.getEntriesByType('navigation');
if (navigationEntries.length > 0) {
const navigationEntry = navigationEntries[0];
const pageLoadTime = navigationEntry.loadEventEnd - navigationEntry.startTime;
console.log(`页面加载时间: ${pageLoadTime} ms`);
}
});
这段代码会在页面加载完成后执行,然后获取 navigation
类型的 PerformanceEntry
,计算 loadEventEnd
和 startTime
的差值,得到页面加载时间。
代码实战:监控资源加载时间
接下来,我们用 PerformanceObserver
来实时监控资源加载时间:
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.entryType === 'resource') {
console.log(`资源 ${entry.name} 加载时间: ${entry.duration} ms`);
}
});
});
observer.observe({ type: 'resource', buffered: true }); // buffered: true 表示获取观察器创建之前已经存在的资源
这段代码会创建一个 PerformanceObserver
对象,当有新的 resource
类型的 PerformanceEntry
被创建时,就会执行回调函数,打印资源加载时间。 buffered: true
确保我们也能获取到在观察器创建之前已经加载的资源。
自定义性能指标:mark
和 measure
的妙用
有时候,我们需要衡量一些特定的功能或操作的性能,这时就可以使用 mark
和 measure
来创建自定义的性能指标。
performance.mark(markName)
: 在代码中创建一个时间戳,用markName
标记。performance.measure(measureName, startMarkName, endMarkName)
: 计算startMarkName
和endMarkName
之间的时间差,用measureName
标记。
代码实战:测量函数执行时间
假设我们要测量一个名为 myFunction
的函数执行时间:
function myFunction() {
performance.mark('myFunctionStart');
// 这里是函数的具体逻辑
for (let i = 0; i < 1000000; i++) {
// 模拟耗时操作
}
performance.mark('myFunctionEnd');
}
myFunction();
performance.measure('myFunctionDuration', 'myFunctionStart', 'myFunctionEnd');
const measureEntries = performance.getEntriesByName('myFunctionDuration', 'measure');
if (measureEntries.length > 0) {
const measureEntry = measureEntries[0];
console.log(`myFunction 执行时间: ${measureEntry.duration} ms`);
}
这段代码首先在 myFunction
函数的开始和结束位置分别创建了 mark
,然后使用 measure
计算了这两个 mark
之间的时间差,最后获取 measure
类型的 PerformanceEntry
,打印函数执行时间。
代码实战:结合 PerformanceObserver
实时监控自定义指标
我们还可以结合 PerformanceObserver
来实时监控自定义指标:
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.entryType === 'measure') {
console.log(`自定义指标 ${entry.name} 耗时: ${entry.duration} ms`);
}
});
});
observer.observe({ type: 'measure', buffered: true });
function doSomething() {
performance.mark('doSomethingStart');
// 一些耗时操作
for (let i = 0; i < 500000; i++) {
// 模拟耗时操作
}
performance.mark('doSomethingEnd');
performance.measure('doSomethingDuration', 'doSomethingStart', 'doSomethingEnd');
}
doSomething();
doSomething(); // 多次执行,观察结果
清理战场:performance.clearMarks()
和 performance.clearMeasures()
随着时间的推移,PerformanceEntry
会越来越多,可能会影响性能。我们可以使用 performance.clearMarks()
和 performance.clearMeasures()
来清理 mark
和 measure
类型的 PerformanceEntry
。
performance.clearMarks('myFunctionStart'); // 清理名为 'myFunctionStart' 的 mark
performance.clearMeasures('myFunctionDuration'); // 清理名为 'myFunctionDuration' 的 measure
性能数据的上报和分析
光有数据还不够,还得把数据上报到服务器,进行分析和可视化。这样才能更好地了解网站的性能状况,并制定相应的优化策略。
常用的上报方式有:
fetch
API: 使用fetch
API 将数据发送到服务器。XMLHttpRequest
: 使用XMLHttpRequest
对象将数据发送到服务器。navigator.sendBeacon()
: 使用navigator.sendBeacon()
方法在页面卸载时发送数据,不会阻塞页面卸载过程。
代码实战:使用 fetch
上报性能数据
function reportPerformanceData(data) {
fetch('/api/performance', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
console.error('性能数据上报失败');
}
})
.catch(error => {
console.error('性能数据上报出错:', error);
});
}
window.addEventListener('load', () => {
const navigationEntries = performance.getEntriesByType('navigation');
if (navigationEntries.length > 0) {
const navigationEntry = navigationEntries[0];
const pageLoadTime = navigationEntry.loadEventEnd - navigationEntry.startTime;
const data = {
pageLoadTime: pageLoadTime,
url: window.location.href
};
reportPerformanceData(data);
}
});
这段代码会在页面加载完成后,获取页面加载时间,然后使用 fetch
API 将数据发送到 /api/performance
接口。
PerformanceEntry
的注意事项
- 性能开销: 频繁地创建
mark
和measure
可能会带来一定的性能开销,需要权衡。 - 数据采样: 在生产环境中,可以采用数据采样的方式,只上报部分用户的性能数据,以减少服务器压力。
- 隐私问题: 注意保护用户隐私,避免上报敏感信息。
- 浏览器兼容性:
PerformanceEntry
的兼容性较好,但仍需注意一些旧版本浏览器的兼容性问题。
总结:PerformanceEntry
,你网站的性能管家
PerformanceEntry
是一个强大的性能监控工具,它可以帮助你了解网站的性能状况,定位性能瓶颈,并制定相应的优化策略。 通过灵活运用 PerformanceEntry
的各种功能,你可以打造一个更快、更流畅、更用户友好的网站!
今天就到这里,希望大家有所收获! 下次再见!