嘿!大家好!我是老码农,今天咱来聊聊 JavaScript 里那些能让你代码跑得飞起的“秘密武器”——Performance API,特别是里面的 performance.now()
和 PerformanceObserver
这俩哥们。
第一节:摸清底细,啥是 Performance API?
咱先别急着上代码,先搞清楚这 Performance API 到底是啥玩意儿。简单来说,它就是浏览器提供的一套工具,让你能够测量和分析你的网页或应用的性能。有了它,你就能知道哪些代码跑得慢,哪些地方需要优化,就像给你的代码做了个体检一样。
Performance API 提供了一系列接口,包括:
performance.now()
: 这个是咱们今天要重点关注的,用来获取高精度的时间戳。performance.mark()
和performance.measure()
: 这俩哥们配合起来,可以让你标记代码中的特定点,然后测量这些点之间的时间差。PerformanceObserver
: 也是今天的主角之一,它能让你监听特定的性能事件,比如长任务(Long Tasks)等。- 还有一些其他的,比如
performance.timing
(已废弃,不建议使用),performance.memory
(非标准,各浏览器支持程度不一) 等,咱们今天先不细聊。
第二节:performance.now()
:时间都去哪儿了?
performance.now()
的作用很简单,就是返回一个高精度的时间戳,单位是毫秒。这个时间戳是相对于页面加载开始的时间的。注意,它不是绝对时间,而是相对时间,所以它不会受到系统时间的影响。
为啥要用 performance.now()
而不是 Date.now()
呢? 主要原因是精度更高。Date.now()
通常只能精确到毫秒级,而 performance.now()
可以精确到微秒级,甚至更高。 这在测量非常短的时间间隔时非常有用。
下面来个简单的例子:
const startTime = performance.now();
// 模拟一些耗时操作
for (let i = 0; i < 1000000; i++) {
// do something
}
const endTime = performance.now();
const duration = endTime - startTime;
console.log(`这段代码执行了 ${duration} 毫秒`);
这个例子非常简单,就是测量一段循环代码的执行时间。通过 performance.now()
获取开始时间和结束时间,然后相减,就能得到代码的执行时间了。
第三节:performance.mark()
和 performance.measure()
:精准定位性能瓶颈
performance.mark()
允许你在代码中标记特定的点,给它们起个名字。 然后 performance.measure()
可以测量两个标记点之间的时间差。
performance.mark('start');
// 模拟一些耗时操作
for (let i = 0; i < 1000000; i++) {
// do something
}
performance.mark('end');
performance.measure('myMeasure', 'start', 'end');
const measure = performance.getEntriesByName('myMeasure')[0];
console.log(`'myMeasure' 这个过程耗时 ${measure.duration} 毫秒`);
在这个例子中,我们分别在循环开始和结束的地方打了两个标记,分别是 ‘start’ 和 ‘end’。 然后使用 performance.measure()
创建了一个名为 ‘myMeasure’ 的测量,指定了开始和结束的标记。 最后,我们使用 performance.getEntriesByName()
获取了 ‘myMeasure’ 的测量结果,并打印了它的持续时间。
你也可以在浏览器的 Performance 面板中看到这些标记和测量结果,能更直观地分析性能。
第四节:PerformanceObserver
:实时监控性能指标
PerformanceObserver
允许你监听特定的性能事件。当这些事件发生时,它会通知你。 这对于实时监控性能指标非常有用,比如长任务(Long Tasks),布局偏移(Layout Shifts)等。
首先,你需要创建一个 PerformanceObserver
实例,并指定要监听的事件类型。 然后,你需要调用 observe()
方法来开始监听。
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`检测到 ${entry.entryType} 事件:`, entry);
// 在这里处理性能事件,比如记录日志、发送报告等
});
});
observer.observe({ entryTypes: ['longtask', 'layout-shift'] });
在这个例子中,我们创建了一个 PerformanceObserver
实例,并指定要监听 ‘longtask’ 和 ‘layout-shift’ 两种事件类型。当有长任务或布局偏移发生时,observer 会调用回调函数,并将事件信息传递给回调函数。
entryTypes
可以是以下值之一:
事件类型 | 描述 |
---|---|
"longtask" |
长任务。 指的是执行时间超过 50 毫秒的任务,通常会导致页面卡顿。 |
"layout-shift" |
布局偏移。指的是页面上的元素在用户没有预期的情况下发生移动,会导致用户体验下降。 |
"mark" |
由 performance.mark() 创建的标记。 |
"measure" |
由 performance.measure() 创建的测量。 |
"resource" |
资源加载事件。 |
"navigation" |
导航事件。 |
"paint" |
渲染事件。 |
"event" |
用户事件,比如点击、键盘输入等。 需要设置eventFilter 才能使用。 |
你可以根据需要监听不同的事件类型,并在回调函数中处理这些事件。
第五节:实战演练:监控长任务
咱们来个更实际的例子,用 PerformanceObserver
监控长任务,并将它们记录到控制台。
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.warn(`发现长任务:`, entry);
console.warn(`长任务的持续时间:${entry.duration} 毫秒`);
console.warn(`长任务的起始时间:${entry.startTime} 毫秒`);
console.warn(`长任务的 attribution:`, entry.attribution); // attribution 包含了导致长任务的脚本信息
});
});
observer.observe({ entryTypes: ['longtask'] });
// 模拟一个长任务
function simulateLongTask() {
const startTime = performance.now();
while (performance.now() - startTime < 100) {
// 阻塞主线程
}
}
// 触发长任务
setTimeout(simulateLongTask, 1000);
在这个例子中,我们创建了一个 PerformanceObserver
实例,监听 ‘longtask’ 事件。当有长任务发生时,我们会在控制台打印长任务的信息,包括持续时间、起始时间和 attribution。
attribution
属性包含了导致长任务的脚本信息,可以帮助你找到导致性能问题的代码。
我们还模拟了一个长任务,它会阻塞主线程 100 毫秒。 当你运行这段代码时,你应该能在控制台看到长任务的信息。
第六节:高级用法:过滤性能事件
PerformanceObserver
还支持过滤性能事件,让你只监听你感兴趣的事件。 你可以使用 eventFilter
选项来过滤事件。
例如,你可以只监听特定类型的用户事件:
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`检测到 ${entry.name} 事件:`, entry);
});
});
observer.observe({
type: 'event',
eventFilter: ['click', 'keydown'], //只监听 click 和 keydown 事件
});
document.addEventListener('click', () => {
console.log('click event');
});
document.addEventListener('keydown', () => {
console.log('keydown event');
});
在这个例子中,我们只监听 ‘click’ 和 ‘keydown’ 事件。 当你点击页面或按下键盘时,observer 就会收到通知。
第七节:停止监听:disconnect()
方法
当你不再需要监听性能事件时,你可以调用 disconnect()
方法来停止监听。
const observer = new PerformanceObserver((list) => {
// ...
});
observer.observe({ entryTypes: ['longtask'] });
// 在某个时候停止监听
observer.disconnect();
调用 disconnect()
方法后,observer 将不再收到任何性能事件的通知。
第八节:最佳实践和注意事项
- 不要过度使用:
PerformanceObserver
会增加页面的开销,所以不要过度使用。 只监听你真正需要的事件。 - 在生产环境中谨慎使用: 在生产环境中,你应该只记录必要的性能数据,避免过度收集数据导致性能下降。
- 使用抽样: 如果需要收集大量的性能数据,可以考虑使用抽样技术,只收集一部分数据。
- 注意浏览器兼容性: 虽然
Performance API
的支持度已经很高了,但还是要注意浏览器兼容性。 可以使用 polyfill 来提供兼容性支持。 - 结合开发者工具使用:
Performance API
配合浏览器的开发者工具使用,效果更佳。 你可以在开发者工具的 Performance 面板中查看更详细的性能数据。 - 避免阻塞主线程: 在
PerformanceObserver
的回调函数中,尽量避免执行耗时的操作,以免阻塞主线程。
第九节:总结
今天我们学习了 JavaScript
的 Performance API
,重点介绍了 performance.now()
和 PerformanceObserver
的用法。 掌握这些工具,可以帮助你更好地了解和优化你的网页或应用的性能,让你的代码跑得更快、更流畅。
记住,性能优化是一个持续的过程,需要不断地学习和实践。 希望今天的分享对你有所帮助!
好了,今天的讲座就到这里。 感谢大家的聆听,咱们下次再见! (挥手)