如何利用 JavaScript 中的 Performance API 监控网页性能指标,例如 Long Tasks, First Contentful Paint (FCP) 和 Largest Contentful Paint (LCP)?

各位靓仔靓女,晚上好!我是你们今晚的性能优化小助手,代号“闪电侠”,专门负责给大家讲讲怎么用 JavaScript 的 Performance API 监控网页性能,让你的网页像吃了德芙一样丝滑!

今天咱们要聊的啊,都是些硬货,都是能直接上手用的技术。别害怕,我会尽量用大白话,把这些看似高深的东西讲得明明白白。咱们的目标是:下次老板再问“网页卡成PPT怎么办?”,你能自信地说:“交给我,保证药到病除!”

咱们今天的议程是:

  1. Performance API 概览: 什么是 Performance API?它能干啥?
  2. Long Tasks: 揪出幕后黑手,让你的主线程不再阻塞。
  3. First Contentful Paint (FCP): 用户第一印象很重要,如何更快地让用户看到东西?
  4. Largest Contentful Paint (LCP): 谁是页面上最大的“功臣”?如何让它更快地出现?
  5. 实战演练: 结合代码,一步一步教你监控这些指标。
  6. 进阶技巧: 一些让你的监控更精准的小技巧。

1. Performance API 概览:性能监控的瑞士军刀

Performance API,顾名思义,就是一套用来测量网页性能的 API。它就像一个瑞士军刀,里面有很多工具,可以帮你测量各种各样的性能指标。

它提供了一系列的接口,让你能够访问浏览器的性能数据。这些数据包括:

  • 时间戳: 记录事件发生的时间,比如页面加载完成的时间,资源加载完成的时间等等。
  • 指标: 计算各种性能指标,比如 FCP、LCP、TTFB 等等。
  • 资源加载信息: 告诉你每个资源加载的时间、大小、类型等等。

有了这些数据,你就可以分析网页的性能瓶颈,找出导致网页卡顿的原因,然后进行优化。

最常用的 Performance API 对象是 performance。你可以通过 window.performance 来访问它。

console.log(window.performance); // 看看它里面都有啥

你会发现,performance 对象里面有很多属性和方法,比如 timingnavigationgetEntries() 等等。这些都是我们分析性能的重要工具。

2. Long Tasks:揪出幕后黑手,让你的主线程不再阻塞

Long Tasks 指的是执行时间超过 50 毫秒的任务。这些任务会阻塞主线程,导致页面卡顿,影响用户体验。想象一下,你在玩游戏,突然卡了一下,是不是很想砸键盘?Long Tasks 就是罪魁祸首。

我们要做的就是找出这些 Long Tasks,然后优化它们,让它们不再阻塞主线程。

Performance API 提供了一个 PerformanceObserver 对象,可以用来监听 Long Tasks。

const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    console.log("Long Task detected:", entry);
    console.log("Duration:", entry.duration);
    console.log("Attribution:", entry.attribution); // 哪个脚本引起的
  });
});

observer.observe({ type: "longtask", buffered: true });

这段代码的意思是:

  1. 创建一个 PerformanceObserver 对象,它会在 Long Task 发生时被调用。
  2. list.getEntries() 获取所有 Long Task 的 PerformanceEntry 对象。
  3. 遍历这些 PerformanceEntry 对象,打印 Long Task 的信息,包括持续时间、哪个脚本引起的等等。
  4. observer.observe({ type: "longtask", buffered: true }) 告诉 PerformanceObserver 对象开始监听 Long Task。buffered: true 表示获取在 observe 之前发生的 longtask。

entry.attribution 会提供更详细的信息,比如哪个脚本文件、哪个函数引起的 Long Task。这对于定位问题非常有帮助。

优化 Long Tasks 的方法:

  • 代码分割: 将大的 JavaScript 文件分割成小的文件,按需加载。
  • 延迟加载: 将不重要的代码延迟加载,比如图片懒加载、组件按需加载等等。
  • Web Workers: 将耗时的任务放到 Web Workers 中执行,避免阻塞主线程。
  • 优化算法: 检查你的代码,看看有没有可以优化的算法,比如避免在循环中进行大量的计算等等。
  • 使用 requestAnimationFrame 将更新 UI 的任务放到 requestAnimationFrame 中执行,让浏览器有时间进行优化。

3. First Contentful Paint (FCP):用户第一印象很重要

First Contentful Paint (FCP) 指的是浏览器首次渲染任何文本、图像、非白色 canvas 或 SVG 的时间。简单来说,就是用户第一次看到页面上有东西出现的时间。

FCP 是一个非常重要的性能指标,因为它直接影响用户的第一印象。如果 FCP 太慢,用户可能会认为你的网站很慢,甚至直接离开。

Performance API 提供了 PerformanceObserver 对象,可以用来监听 FCP。

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
    console.log('FCP candidate:', entry.startTime, entry);
  }
}).observe({ type: 'paint', buffered: true });

这段代码的意思是:

  1. 创建一个 PerformanceObserver 对象,它会在 FCP 发生时被调用。
  2. entryList.getEntriesByName('first-contentful-paint') 获取 FCP 的 PerformanceEntry 对象。
  3. 打印 FCP 的信息,包括发生的时间等等。
  4. observer.observe({ type: 'paint', buffered: true }) 告诉 PerformanceObserver 对象开始监听 FCP。

优化 FCP 的方法:

  • 减少 HTTP 请求: 减少页面上的 HTTP 请求,比如合并 CSS 文件、JavaScript 文件等等。
  • 优化 CSS: 避免使用阻塞渲染的 CSS,比如将 CSS 放在 <head> 标签中,避免使用 @import 等等。
  • 优化 JavaScript: 避免使用阻塞渲染的 JavaScript,比如将 JavaScript 放在 <body> 标签的底部,使用 asyncdefer 属性等等。
  • 使用 CDN: 使用 CDN 可以将你的资源分发到全球各地,让用户可以更快地访问你的网站。
  • 服务器优化: 优化你的服务器,让它可以更快地响应请求。
  • 预加载关键资源: 使用 <link rel="preload"> 预加载关键资源,比如字体、图片等等。

4. Largest Contentful Paint (LCP):谁是页面上最大的“功臣”?

Largest Contentful Paint (LCP) 指的是视窗内最大的内容元素渲染完成的时间。这个内容元素可以是图片、视频、文本块等等。

LCP 也是一个非常重要的性能指标,因为它代表了用户主要内容加载完成的时间。如果 LCP 太慢,用户可能会认为你的网站很慢,甚至直接离开。

Performance API 提供了 PerformanceObserver 对象,可以用来监听 LCP。

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP candidate:', entry.startTime, entry);
    console.log('LCP element:', entry.element); // 哪个元素是LCP
    console.log('LCP size:', entry.size); // 元素大小
  }
}).observe({ type: 'largest-contentful-paint', buffered: true });

这段代码的意思是:

  1. 创建一个 PerformanceObserver 对象,它会在 LCP 发生时被调用。
  2. entryList.getEntries() 获取 LCP 的 PerformanceEntry 对象。
  3. 打印 LCP 的信息,包括发生的时间、哪个元素是 LCP 等等。
  4. observer.observe({ type: 'largest-contentful-paint', buffered: true }) 告诉 PerformanceObserver 对象开始监听 LCP。

优化 LCP 的方法:

  • 优化图片: 压缩图片,使用合适的图片格式,使用 srcset 属性等等。
  • 优化字体: 使用 Web Font Loader,避免字体闪烁,使用 font-display 属性等等。
  • 优化视频: 压缩视频,使用合适的视频格式,使用 preload 属性等等。
  • 优化服务器: 优化你的服务器,让它可以更快地响应请求。
  • 使用 CDN: 使用 CDN 可以将你的资源分发到全球各地,让用户可以更快地访问你的网站。
  • 预加载 LCP 元素: 使用 <link rel="preload"> 预加载 LCP 元素。
  • 服务端渲染 (SSR): 使用服务端渲染可以更快地渲染页面,提高 LCP。

5. 实战演练:结合代码,一步一步教你监控这些指标

现在,让我们结合代码,一步一步教你如何监控 Long Tasks、FCP 和 LCP。

步骤 1:创建 HTML 文件

创建一个 HTML 文件,命名为 index.html,内容如下:

<!DOCTYPE html>
<html>
<head>
  <title>Performance Monitoring</title>
  <style>
    body {
      font-family: sans-serif;
    }
    img {
      width: 500px;
    }
  </style>
</head>
<body>
  <h1>Performance Monitoring</h1>
  <img src="https://via.placeholder.com/500" alt="Placeholder Image">
  <script src="script.js"></script>
</body>
</html>

步骤 2:创建 JavaScript 文件

创建一个 JavaScript 文件,命名为 script.js,内容如下:

// Long Tasks
const longTaskObserver = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    console.log("Long Task detected:", entry);
    console.log("Duration:", entry.duration);
    console.log("Attribution:", entry.attribution);
  });
});

longTaskObserver.observe({ type: "longtask", buffered: true });

// FCP
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
    console.log('FCP candidate:', entry.startTime, entry);
  }
}).observe({ type: 'paint', buffered: true });

// LCP
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP candidate:', entry.startTime);
    console.log('LCP element:', entry.element);
  }
}).observe({ type: 'largest-contentful-paint', buffered: true });

// Simulate a long task
function simulateLongTask() {
  const start = performance.now();
  while (performance.now() - start < 100) {
    // Do nothing, just block the main thread
  }
  console.log("Long task completed");
}

setTimeout(simulateLongTask, 2000); // Simulate after 2 seconds

这段代码会监听 Long Tasks、FCP 和 LCP,并将它们的信息打印到控制台。还会模拟一个 Long Task,方便你测试。

步骤 3:在浏览器中打开 HTML 文件

在浏览器中打开 index.html 文件,打开开发者工具,查看控制台。

你会看到 Long Tasks、FCP 和 LCP 的信息被打印到控制台。

6. 进阶技巧:让你的监控更精准

  • 使用 performance.mark()performance.measure() 你可以使用 performance.mark() 标记代码的开始和结束时间,然后使用 performance.measure() 计算代码的执行时间。这可以帮助你更精确地测量代码的性能。
performance.mark('start');

// Your code here

performance.mark('end');

performance.measure('My Code', 'start', 'end');

const measure = performance.getEntriesByName('My Code')[0];
console.log('My Code duration:', measure.duration);
  • 使用 User Timing API: User Timing API 允许你自定义性能指标,并将其添加到 Performance API 中。这可以让你更好地监控你的应用程序的性能。

    performance.mark('myCustomEventStart');
    
    // 执行一些操作...
    
    performance.mark('myCustomEventEnd');
    
    performance.measure('myCustomEvent', 'myCustomEventStart', 'myCustomEventEnd');
    
    const measure = performance.getEntriesByName('myCustomEvent')[0];
    console.log('Custom event duration:', measure.duration);
  • 结合第三方工具: 你可以将 Performance API 与第三方工具结合使用,比如 Google Analytics、New Relic 等等。这些工具可以帮你更好地分析性能数据,并提供更详细的报告。
  • 在真实环境中测试: 在真实环境中测试你的代码,可以让你更好地了解你的应用程序的性能。

表格总结:常用Performance API

API 对象/方法 描述 用途
window.performance 整个Performance API 的入口点。 访问所有性能相关的数据和方法。
performance.timing 包含页面加载过程中各个关键时间点的时间戳。 已弃用,不推荐使用。 不推荐使用。 曾经用于计算页面加载时间,但已被更精确的 API 替代。
performance.navigation 提供关于页面导航的信息,例如导航类型(type)。 已弃用,不推荐使用。 不推荐使用。 提供页面导航类型信息。
performance.getEntries() 返回一个 PerformanceEntry 对象数组,包含所有已记录的性能事件(例如资源加载、标记、测量等)。 获取所有性能相关条目,用于分析各种性能指标。
performance.getEntriesByType(type) 返回指定类型的 PerformanceEntry 对象数组。 type 可以是 'resource''mark''measure' 等。 获取特定类型的性能条目,例如所有资源加载条目。
performance.getEntriesByName(name, type) 返回指定名称和类型的 PerformanceEntry 对象数组。 获取具有特定名称的性能条目,例如具有特定名称的标记或测量。
PerformanceObserver 用于监听特定类型的性能事件,并在事件发生时执行回调函数。 实时监控性能指标,例如 Long Tasks、FCP、LCP 等。
performance.mark(name) 在时间线上创建一个标记,用于记录特定事件的时间点。 标记代码执行的开始和结束时间,以便稍后进行测量。
performance.measure(name, startMark, endMark) 创建一个测量,计算从 startMarkendMark 的时间差。 测量代码的执行时间,用于分析代码的性能。
performance.clearMarks(name) 清除指定名称的标记。 清除不再需要的标记,避免影响后续的测量。
performance.clearMeasures(name) 清除指定名称的测量。 清除不再需要的测量,避免影响后续的分析。
performance.now() 返回一个高精度的时间戳,表示从页面加载开始经过的时间(以毫秒为单位)。 测量代码的执行时间,精度比 Date.now() 更高。

总结:

今天我们学习了如何使用 JavaScript 的 Performance API 监控网页性能指标,包括 Long Tasks、FCP 和 LCP。希望这些知识能帮助你优化你的网页,让你的用户拥有更好的体验。

记住,性能优化是一个持续的过程,需要不断地监控、分析和改进。只要坚持下去,你的网页一定会变得更快更流畅!

好了,今天的讲座就到这里。感谢大家的观看,希望对大家有所帮助!如果有什么问题,欢迎随时提问。咱们下次再见! 溜了溜了!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注