性能监控
前端性能监控是指通过监控前端应用的性能指标、响应时间、资源加载情况等,实时掌握用户体验和应用性能的状况,及时发现潜在问题并优化。前端性能监控是确保应用高效、流畅运行的重要环节,尤其在大型应用中至关重要。
前端性能监控的主要指标
加载时间:
- 页面加载时间:从请求开始到页面渲染完成所需的时间。
- 首屏加载时间:即用户看到页面内容的时间,通常指的是 HTML 和主要资源(如 CSS、JS、图片)的加载时间。
- 资源加载时间:每个资源(CSS、JS、图片等)加载的时间。
响应时间:
- 首次响应时间(First Response Time, FRT):从用户发起请求到浏览器收到响应的时间。
- 时间到交互(Time to Interactive, TTI):页面加载完成并且用户可以与页面进行交互的时间。
渲染性能:
- 帧率:通常以 FPS(每秒帧数)来衡量,理想的帧率是 60 FPS(16ms/帧),低于此帧率会导致页面卡顿。
- 重绘和回流:浏览器在渲染页面时会对元素进行重绘或回流,频繁的回流和重绘会导致性能下降。
JavaScript 性能:
- 执行时间:JavaScript 的执行时间,过长的执行时间会导致页面卡顿。
- 事件处理器执行时间:用户与页面交互时,事件处理器的执行时间也会影响响应速度。
网络请求和带宽:
- API 响应时间:请求 API 时,网络延迟、服务器响应速度等都会影响性能。
- 请求数量:页面加载时发起的 HTTP 请求数量,过多的请求会增加加载时间。
错误监控:
- JavaScript 错误:捕捉页面中出现的 JavaScript 错误,影响页面的执行和用户体验。
- 资源加载失败:如 CSS、JS、图片等资源加载失败的监控。
性能监控的主要技术
Performance API:
- 浏览器提供的原生
Performance API
可以获取页面加载时间、资源加载时间、脚本执行时间等指标。 - 常用的 API:
performance.now()
:返回高精度的时间戳,通常用于测量代码执行的时间。performance.mark()
和performance.measure()
:可以手动标记代码执行的时间节点并计算时间间隔。
- 浏览器提供的原生
Window.performance:
- 提供了获取页面加载信息的方法,如
performance.timing
,该属性包含了各种与页面加载相关的时间信息。 - 常用属性:
performance.timing.navigationStart
:页面导航开始的时间。performance.timing.loadEventEnd
:页面加载完成的时间。
- 提供了获取页面加载信息的方法,如
Google Lighthouse:
- Lighthouse 是一个开源的自动化工具,可以评估网页的性能、可访问性、SEO、PWA 等。
- 它提供了详细的性能报告,包括关键性能指标(如 FCP、LCP、FID、CLS)以及优化建议。
- 适用于在开发阶段或部署后对应用进行性能检测。
Web Vitals:
- Web Vitals 是 Google 推出的一个指标集合,旨在帮助开发者监控和优化用户体验。
- 主要包括三大核心指标:
- Largest Contentful Paint (LCP):页面最大内容绘制时间,衡量页面的加载性能。
- First Input Delay (FID):首次输入延迟,衡量用户与页面交互的响应时间。
- Cumulative Layout Shift (CLS):累计布局偏移,衡量页面内容布局的稳定性。
- 通过
web-vitals
库可以轻松集成并收集 Web Vitals 数据。
监控服务集成:
- 使用第三方监控服务,如:
- Sentry:除了错误监控,Sentry 也提供性能监控,能够捕捉到页面加载性能、用户互动时间等。
- New Relic:提供前端性能监控,支持 JavaScript 事务追踪、页面性能监控、API 性能监控等。
- Datadog:前端性能监控、日志记录和应用追踪,能够帮助开发者深入了解应用的性能瓶颈。
- 使用第三方监控服务,如:
特性 | Sentry | New Relic | Datadog |
---|---|---|---|
主要功能 | 错误监控 + 性能监控 | 性能监控 + 事务追踪 | 性能监控 + 日志管理 + 基础设施监控 |
适用场景 | 错误排查和基础性能监控 | 企业级应用的全面性能监控 | 全栈应用的性能监控与日志管理 |
功能亮点 | 错误追踪、JavaScript 错误捕获 | 强大的 APM 支持,全面的事务追踪 | 完整的监控平台,支持分布式追踪 |
优点 | 易于集成、支持多平台、详细的错误堆栈 | 精确的性能监控、事务追踪能力强 | 全面的性能监控与日志管理,适合复杂环境 |
缺点 | 性能监控较基础,功能不够全面 | 学习曲线较陡,价格较高 | 对小型应用可能过于复杂,定价较高 |
适用规模 | 中小型应用、开发阶段 | 中大型企业级应用 | 大型应用、微服务架构、全栈监控 |
价格 | 免费套餐,按需计费 | 需要付费,高级功能较为昂贵 | 按需计费,价格较高 |
性能监控的实践技巧
按需加载资源:
- 采用懒加载、按需加载技术,减少页面初次加载时的资源请求数量,缩短页面加载时间。
- 使用动态
import()
实现按需加载 JS 文件,使用IntersectionObserver
实现懒加载图片。专题版块详见 懒加载图片。
js// 需要时才加载模块 button.addEventListener("click", () => { import("./largeModule.js").then((module) => { module.loadData(); }); });
优化 JavaScript 执行:
- 将 JavaScript 代码拆分成多个小模块,使用 Webpack、Vite 等构建工具进行代码分割(code splitting)。
- Webpack 支持几种不同的代码拆分方式:入口拆分、块拆分和 动态拆分。
- 避免长时间运行的 JavaScript 任务,使用
Web Workers
进行后台处理。- 长时间运行的 JavaScript 任务(例如复杂的计算、大量数据处理)可能会导致浏览器卡顿,影响用户体验。使用
Web Workers
可以将这类任务移至后台线程,在不阻塞主线程的情况下处理大量数据或复杂计算。
- 长时间运行的 JavaScript 任务(例如复杂的计算、大量数据处理)可能会导致浏览器卡顿,影响用户体验。使用
创建和使用
Web Worker
在主线程中,通过
Worker
构造函数来创建一个新的Web Worker
实例。Web Worker
会在后台线程中执行脚本,主线程与Worker
通过postMessage
和onmessage
事件进行通信。js// main.js const worker = new Worker("worker.js"); // 向 Worker 发送数据 worker.postMessage("Start processing"); // 接收 Worker 返回的数据 worker.onmessage = function (e) { console.log("Result from worker:", e.data); }; // worker.js onmessage = function (e) { console.log("Worker received:", e.data); // 处理任务 let result = performComplexCalculation(); postMessage(result); // 将结果传回主线程 }; function performComplexCalculation() { // 假设这是一个复杂的计算 return 42; }
注意
- 在浏览器中,Worker 是原生支持的,因此没有问题。
- 在 Node.js 环境中,Worker 需要通过 worker_threads 模块来实现多线程功能。
如果你希望在浏览器环境中使用 Web Worker,而又不想让代码在 Node.js 中报错,可以通过条件判断来判断代码运行环境:
js// 这将确保代码在浏览器中正常执行,而在 Node.js 环境中不会报错。 if (typeof Worker !== "undefined") { const worker = new Worker("worker.js"); } else { console.log("Web Workers are not supported in this environment"); }
- 将 JavaScript 代码拆分成多个小模块,使用 Webpack、Vite 等构建工具进行代码分割(code splitting)。
优化网络请求:
- 使用 HTTP/2 或 HTTP/3 协议,减少请求的延迟。
- 压缩资源文件,如使用 Gzip(源于 1992 年)、Brotli(2015 年首次发布) 压缩 JS、CSS 文件。
- Gzip 和 Brotli 都是常用的文件压缩算法,Brotli 是相较于 Gzip 更高效的压缩算法,尤其在文本文件压缩方面具有更高的压缩比。
- Brotli 压缩 能显著提升 Web 应用的加载速度,尤其对于大型静态资源文件(如 JS、CSS、HTML 文件)。
- 减少 HTTP 请求的数量,合并 CSS 和 JS 文件,使用图片精灵(sprites)等技术。
特性 | Gzip | Brotli |
---|---|---|
压缩率 | 较低,通常比 Brotli 差 20-30% | 较高,比 Gzip 提供更好的压缩率 |
速度 | 较快,压缩和解压速度较高 | 相对较慢,特别是压缩速度较低 |
支持度 | 几乎所有的浏览器、Web 服务器和 CDN 都支持 | 现代浏览器支持较好(Chrome、Firefox、Edge、Safari) |
使用场景 | 适用于压缩速度较为敏感的场合,且兼容性要求较高 | 适用于需要优化带宽和加载时间的场合,尤其是 HTTP/2 和 HTTP/3 中 |
主要应用 | 用于 Web 页面和文件的 HTTP 压缩 | 用于 Web 页面、文件的 HTTP 压缩和更高效的带宽利用 |
优化方法 | 原理 | 应用场景 | 实现方法 |
---|---|---|---|
HTTP/2 / HTTP/3 | 多路复用、头部压缩、服务器推送,减少延迟 | 并发请求多、数据传输效率要求高的场景 | 配置服务器支持 HTTP/2 或 HTTP/3。 |
资源压缩 | 使用 Gzip 或 Brotli 压缩算法减少文件体积,提升加载速度 | 所有静态资源(JS、CSS、HTML) | 配置服务器支持 Gzip 或 Brotli,构建工具压缩资源。 |
减少请求数量 | 合并文件、使用图片精灵(英语:Sprite,又称“雪碧图”)等技术减少 HTTP 请求次数 | 静态资源多且独立、图标和小图片的场景 | 配置 Webpack、Parcel 进行资源合并,使用图片精灵工具。 |
Nginx 配置 Brotli
- 安装 Brotli 模块
# 如果你是通过 apt 安装的 Nginx,可以使用以下命令来安装 Brotli 模块
sudo apt-get install nginx-module-brotli
- 在 Nginx 配置文件中启用 Brotli: 在
nginx.conf
中启用 Brotli 压缩:
http {
brotli on;
# brotli_comp_level 设置 Brotli 压缩的级别(1-11,数字越大,压缩率越高,但性能开销越大)。
brotli_comp_level 5;
# brotli_types 指定哪些 MIME 类型的文件需要使用 Brotli 压缩。
brotli_types text/plain text/css application/javascript application/json application/xml application/xhtml+xml image/svg+xml;
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
}
}
}
- 重启 Nginx 服务器: 完成配置后,重启 Nginx 使设置生效:
sudo systemctl restart nginx
Vite 配置 Brotli
- 安装 vite-plugin-compression 插件:
npm install vite-plugin-compression --save-dev
- 配置 Vite 启用 Brotli:
import ViteCompression from "vite-plugin-compression";
export default {
plugins: [
ViteCompression({
algorithm: "brotli",
threshold: 10240, // 只有大于 10KB 的文件才会压缩
}),
],
};
如何查看浏览器对 Brotli
的支持情况
- 使用浏览器开发者工具检查响应头
- 打开浏览器的开发者工具(F12)。
- 在 Network(网络)选项卡中,加载你的页面或资源。
- 选择某个静态资源(如 JS、CSS 文件等),查看它的响应头(Response Headers)。
- 检查 Content-Encoding 字段:
- 如果响应头中包含 Content-Encoding: br,则表示该资源使用了 Brotli 压缩。
csscontent-encoding: br;
- 使用浏览器支持情况工具 你也可以通过工具查看浏览器对 Brotli 的支持情况。常见的工具是 Can I use,它会显示不同浏览器对 Brotli 的支持情况。
- 访问 Can I use 查看详细的浏览器支持情况。
哪些网站是开启 Brotli 压缩的?
- Google: https://www.google.com
- 作为 Brotli 的发明者,Google 在自己的站点和服务中广泛使用 Brotli 压缩来加速页面加载,尤其是在 Google 搜索和 Google Ads 等页面上。
- Facebook: https://www.facebook.com
- YouTube: https://www.youtube.com
- Twitter: https://www.twitter.com
- Amazon: https://www.amazon.com
- Microsoft: https://www.microsoft.com
- Mozilla: https://www.mozilla.org
- Cloudflare: https://www.cloudflare.com
- Wikipedia: https://www.wikipedia.org
- Netflix: https://www.netflix.com
- Slack: https://slack.com
- GitHub: https://www.github.com
优化渲染性能:
避免不必要的重绘和回流,减少 DOM 操作。
使用
requestAnimationFrame()
进行动画优化,避免阻塞渲染线程。requestAnimationFrame()
是浏览器提供的一个 API,用于请求浏览器在下一次重绘之前执行动画操作。- 高效调度:requestAnimationFrame() 会在浏览器的重绘周期内执行,避免了过多的 JavaScript 执行,这有助于降低 CPU 和内存的负担。
- 减少卡顿:因为它在刷新率匹配的时间点执行,所以动画会平滑且流畅。
jsfunction animate() { // 更新动画状态 const element = document.getElementById("box"); const currentLeft = parseFloat(element.style.left || 0); element.style.left = currentLeft + 1 + "px"; // 请求下一帧动画 requestAnimationFrame(animate); } // 启动动画 requestAnimationFrame(animate);
使用 CSS3 动画替代 JavaScript 动画,提升性能。
- CSS3 动画通常比 JavaScript 动画更高效,因为它们由浏览器的渲染引擎直接处理,避免了 JavaScript 的计算开销和频繁 DOM 操作。CSS 动画可以利用 GPU 加速,尤其是当涉及到
transform
和opacity
时。
css/* CSS3动画 */ @keyframes moveRight { 0% { left: 0; } 100% { left: 100px; } } #box { position: absolute; animation: moveRight 2s infinite linear; }
- CSS3 动画通常比 JavaScript 动画更高效,因为它们由浏览器的渲染引擎直接处理,避免了 JavaScript 的计算开销和频繁 DOM 操作。CSS 动画可以利用 GPU 加速,尤其是当涉及到
前端性能监控的自动化:
- 定期使用 Lighthouse、Web Vitals 等工具进行性能检测,并根据分析报告进行优化。
- 将性能监控集成到 CI/CD 流程中,自动化性能回归检测,确保每次发布都不会影响性能。
- 可以使用 Lighthouse CI 集成到 CI/CD 流程中,自动化运行 Lighthouse 检测,生成报告并与之前的性能基准进行对比。
性能监控应用场景
实时监控应用性能:
- 适用于需要实时监控前端性能的应用,能够第一时间发现并解决性能瓶颈。
- 常见应用:电商网站、社交媒体平台、大型 SaaS 应用等。
大规模网站和应用的性能评估:
- 适用于大规模、高流量网站或应用,能够帮助开发者了解不同用户设备和网络环境下的性能表现。
- 常见应用:新闻网站、视频平台、金融平台等。
提升用户体验:
- 通过实时监控和优化前端性能,提升页面加载速度和交互响应速度,改善用户体验。
- 常见应用:新闻网站、博客平台、在线商店等。
总结
前端性能监控是提升应用用户体验的关键部分,通过对页面加载时间、资源加载、JavaScript 执行、网络请求、渲染性能等多个指标的监控,帮助开发者及时发现并优化性能瓶颈。结合 Performance API、Web Vitals、Lighthouse 等工具,开发者可以有效监控和优化前端性能,提升用户体验。