一篇文章说明白web前端性能优化

256 阅读11分钟

一、web前端有哪些性能指标

1. FCP (First Contentful Paint) - 首次内容绘制

定义:测量页面从开始加载到浏览器首次渲染任何文本、图片或非空白Canvas/SVG内容的时间点。

重要性:回答"用户什么时候能看到内容?"的问题,是用户感知加载体验的第一个关键节点。

示例:导航栏logo或标题文字最先显示出来的时刻。

2. LCP (Largest Contentful Paint) - 最大内容绘制

定义:测量视窗内最大内容元素(通常是图片、视频或大段文本块)完全渲染完成的时间。

重要性:反映用户真正看到"主要内容"的时间,直接影响用户对页面速度的感知。

示例:电商网站首屏的主图或新闻网站的文章标题区域完成加载的时刻。

3. FID (First Input Delay) - 首次输入延迟

定义:记录用户第一次与页面交互(点击按钮、输入文字等)到浏览器实际响应这个交互的时间差。

重要性:衡量页面的交互响应速度,数值过大会让用户感觉页面"卡顿"。

示例:点击登录按钮后,到出现响应(如弹窗或跳转)之间的延迟时间。

4. CLS (Cumulative Layout Shift) - 累积布局偏移

定义:计算页面生命周期内发生的所有意外布局偏移的总分数(基于偏移距离和影响范围)。

重要性:量化页面内容的视觉稳定性,避免用户因突然的布局移动而误点。

示例:广告加载后把正文内容突然挤下去,或图片加载导致下方按钮位置移动。

5. 资源加载时间

定义:页面中各种资源(JS/CSS/图片/字体等)从发起请求到完全下载的时间。

重要性:直接影响整体加载性能,特别是关键资源的加载会阻塞渲染。

示例:一个100KB的CSS文件从开始下载到完成用了800ms。

6. 包体积分析

定义:对前端打包产物的分析,包括总大小、各模块占比及未使用代码等。

重要性:过大的包体积会显著延长下载和解析时间,特别是对移动端用户。

示例:发现打包后的JS中有30%是未使用的冗余代码。

为什么这些指标重要?

这些指标共同构成了Web Vitals核心用户体验指标:

  • 加载体验:FCP/LCP
  • 交互体验:FID
  • 视觉稳定性:CLS

Google已明确将这些指标作为搜索排名因素,同时它们也直接关系到用户留存率(LCP每提升100ms,转化率可能提升1%)。

二、如何监测性能指标

现代浏览器提供了多种工具来帮助开发者分析和优化Web产品的性能。这里以谷歌浏览器(Edge、Firefox都可以)为例。 首先打开控制台:F12Ctrl+Shift+I (Mac: Cmd+Opt+I))

1、Performance

Performance 面板是 Chrome 开发者工具中用于分析网页运行时性能的核心工具,它可以帮助你识别卡顿、延迟和其他性能问题。以下是 Performance 面板的主要内容和功能:

image.png

(1)基本组成部分

1)控制区域

  • 记录按钮:开始/停止记录性能数据
  • 清除按钮:清除当前记录
  • 加载时记录:自动记录页面加载过程
  • 屏幕截图:记录期间捕获屏幕截图(可选)

2)主视图区域

  • 概览面板:显示 FPS、CPU 使用率和网络请求的总体情况
  • 火焰图(Flame Chart):详细显示主线程活动
  • 细节面板:选中具体事件后显示详细信息

(2)关键性能指标

在记录后会显示以下关键指标:

  • FPS (帧率):动画和滚动的流畅度
  • CPU 使用率:各进程的 CPU 消耗
  • 网络活动:资源加载情况

(3)火焰图详解

1)Main (主线程) 部分

  • 调用栈:显示 JavaScript 执行调用栈
  • 任务:显示长任务(超过50ms的任务会被标记为红色)
  • 函数调用:显示具体执行的函数

2)其他线程部分

  • Raster:光栅化线程活动
  • GPU:GPU 活动
  • Compositor:合成器线程活动

(4)底部详情面板

选中具体事件后显示:

  • Summary 标签:事件类型和总耗时
  • Bottom-Up 标签:按耗时排序的函数调用
  • Call Tree 标签:完整的调用树
  • Event Log 标签:按时间顺序排列的事件日志

(5)性能分析流程

1)开始记录:点击记录按钮或使用快捷键(Ctrl+E) ;
2)执行操作:执行你想要分析的页面交互 ;
3)停止记录:再次点击记录按钮 ;
4)分析结果:检查长任务(红色标记)、查看高耗时函数、分析布局抖动(频繁的 Layout 操作)、检查不必要的重绘/重排。

通过 Performance 面板,开发者可以深入了解页面运行时的性能瓶颈,找出导致卡顿的具体原因,并进行有针对性的优化。

2、Lightohuse

Lighthouse 是 Google 开发的开源自动化工具,用于评估和改进网页质量。 image.png

(1)基本组成部分

1)五大核心审计维度

维度检测重点商业价值
性能(Performance)加载速度、交互响应时间降低跳出率,提升转化
无障碍(Accessibility)残障用户可访问性法律合规,扩大用户群
最佳实践(Best Practices)安全、现代Web标准提升技术健壮性
SEO搜索引擎优化提高自然流量
PWA渐进式Web应用特性增强移动端体验

2)关键性能指标

  • LCP (最大内容渲染):测量加载性能(优≤2.5s)
  • FID (首次输入延迟):测量交互响应(优≤100ms)
  • CLS (布局稳定性):测量视觉稳定性(优≤0.1)
  • TBT (总阻塞时间):测量主线程阻塞(优≤300ms)

(2)性能分析流程

1) F12 打开开发者工具 → 切换到 Lighthouse 面板
2) 配置选项:
设备模拟:Mobile / Desktop
审计范围:勾选需要的类别
节流设置:模拟慢速网络/CPU(默认:Simulated throttling)
3) 点击 Analyze page load
4) 查看交互式报告:分数解读(0-100分)、优化建议(按影响排序)、原始指标数据

3、Coverage

Coverage(代码覆盖率)是浏览器开发者工具中的一项功能,用于分析网页加载的CSS和JavaScript代码中有多少比例在实际运行中被使用。它能帮助开发者识别和移除未使用的代码,优化页面性能。

image.png

(1)基本组成部分

1)主要功能

  • 检测未使用的代码:精确到行级的CSS/JS使用情况分析
  • 量化资源浪费:计算未使用字节占比
  • 定位优化目标:可视化展示代码使用热图

2)三大核心指标

指标说明优化价值
未使用字节文件总大小 - 已使用大小直接减少传输体积
使用百分比(已使用行数/总行数)×100%评估代码效率
关键资源占比首屏使用代码比例优化LCP指标

(2)性能分析流程

1) 打开Coverage面板:
首先打开控制台:F12Ctrl+Shift+I (Mac: Cmd+Opt+I))。在控制台中点击右上角的三个点->More Tools->Coverage,打开面板后点击

2) 录制与分析:点击reload按钮进行分析

3) 解读报告

  • 红色高亮:未执行代码
  • 无高亮:已执行代码

通过Coverage工具,开发者可以数据驱动地进行精准的代码优化,有效减少资源浪费,提升页面加载性能。建议将覆盖率检查纳入常规开发流程,结合打包分析工具持续监控。

三、如何优化性能

在此章节以某平台为例进行性能优化,该平台使用技术如下:

  • 前端框架: Vue 3.5
  • UI 框架: Element Plus 2.8.6
  • 图表库: ECharts 5.3.0、AntV X6 2.18.1
  • 前后端交互: Axios 0.19.2

当前平台的整体性能情况如下: image.png

image.png

1. 分包

由于Spa项目主要就是Js文件体积大,在项目优化的时候,除了通过实际观测每次加载时间外,最为直观的优化成果就是主包大小,就是入口包大小,以及整体项目的体积。

  • 入口包小,意味着首屏加载快;
  • 项目资源体积小,意味着浏览器加载的时间更短。

vue.config.js build中增加如下分包配置:

 rollupOptions: {
        output: {
          // Static resource classification and packaging
          chunkFileNames: 'assets/js/[name]-[hash].js',
          entryFileNames: 'assets/js/[name]-[hash].js',
          assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
            manualChunks: {
              vue: ['vue'],
              'vue-router': ['vue-router'],
              pinia: ['pinia'],
              mitt: ['mitt'],
              axios: ['axios'],
              'element-plus': ['element-plus'],
              dayjs: ['dayjs'],
              echarts: ['echarts'],
              'lodash-es': ['lodash-es'],
              vuetify: ['vuetify'],
            },
        },
      },

分包后: 6021552ddf2d8348e161efd0b6d34b18.png

eab4eecdd3ca7d3fb4239a66182526e2.png 分包前主包大小为1.9MB;分包后主包大小为274KB,主包小了7倍。 FCP、LCP基本没有变化。我猜测是因为项目小,基本看不出变化,大家可以试试自己项目有啥变化没。

2.按需引入

按需引入(On-Demand Import)是前端性能优化的重要手段之一,它能显著减少应用的初始加载体积,提升首屏渲染速度。以下是该项目中按需引入一些第三方包的案例:

(1)echarts按需引入

1)新建echarts.js

// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';

/** 引入柱状图 + 折线图 + 饼图,图表后缀都为 Chart,一般常用的就这三个,如果还需要其他的,就自行添加  */
import {
  BarChart,
  LineChart,
  PieChart,
  GaugeChart,
  CustomChart,
  TreeChart,
  GraphChart,
  ScatterChart,
} from 'echarts/charts';

// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  ToolboxComponent,
  LegendComponent,
  PolarComponent,
  DataZoomComponent,
} from 'echarts/components';

// 标签自动布局,全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';

// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers';

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  ToolboxComponent,
  LegendComponent,
  PolarComponent,
  DataZoomComponent,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer,
  BarChart,
  LineChart,
  PieChart,
  GaugeChart,
  CustomChart,
  TreeChart,
  GraphChart,
  ScatterChart,
]);

// 导出
export default echarts;

2)全局引入echarts.js

import echarts from './utils/echarts.js';
app.provide('$echarts', echarts); 

3)使用echarts

const echarts = inject('$echarts');

可以通过上文说的Coverage看到echarts包显著减小,且利用率提升。但各项性能指标变化不大...

(2)element-plus按需引入

// 安装按需引入插件
npm install -D unplugin-vue-components unplugin-auto-import

// vite.config.js
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
plugins: [
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],

记得把全局引入的element-plus去掉。

// import ElementPlus from 'element-plus';
// import 'element-plus/dist/index.css';
// app.use(ElementPlus, { locale: zhCn })

按需引入之前:

image.png image.png

按需引入之后:

image.png image.png

3.压缩资源

(1)gzip压缩静态资源

Gzip 压缩通过算法减小文本资源的体积,是提升网页性能的 低成本高收益 优化手段。优先对静态资源预生成 .gz 文件(如通过 Webpack/Vite 插件),或在服务器(如 Nginx)中启用动态压缩。此处介绍静态资源预生成 .gz 文件的方式。 整体逻辑如下图所示:\ deepseek_mermaid_20250708_be4663.png vite需要配置内容如下:

// vite.config.js
import viteCompression from 'vite-plugin-compression'
export default {
  plugins: [
    viteCompression({
      algorithm: 'gzip',
      ext: '.gz',
      threshold: 10240,
      deleteOriginFile: false // 是否删除原文件
    })
  ]
}

以echarts为例,压缩前:

image.png 压缩后: image.png 由于服务端同学还没腾出时间配合修改,暂无法看改后效果,改后再补充......

(2)压缩图片资源

//安装 vite-plugin-imagemin插件:
npm i vite-plugin-imagemin -D
//在vite.config.js里面配置
import viteImagemin from 'vite-plugin-imagemin'
// 在plugins配置数组里添加
plugin: [
   viteImagemin({
        gifsicle: {
          interlaced: true, // 隔行扫描
          optimizationLevel: 3, // 压缩级别(0-3)
        },
        optipng: {
          optimizationLevel: 5, // 压缩级别(0-7),值越大压缩率越高
        },
        mozjpeg: {
          quality: 80, // 压缩质量(0-100)
          progressive: true, // 渐进式加载
          smooth: 2, // 平滑处理,减少色彩失真
        },
        svgo: {
          plugins: [
            { name: 'removeViewBox', active: false }, // 保留 viewBox 以防止 SVG 变形
            { name: 'removeEmptyAttrs', active: true }, // 移除空属性
            { name: 'convertColors', params: { currentColor: true } }, // 颜色转换
          ]
        },
        webp: {
          quality: 80, // WebP 质量(0-100)
          lossless: false, // 是否无损压缩
          method: 6, // 压缩方法(0-6),数值越大,压缩率越高但速度变慢
        },
        pngquant: {
          quality: [0.8, 0.9], // PNG 质量范围
          speed: 4, // 压缩速度(1-10),数值越大速度越快但压缩率降低
        },
        disable: !IS_PRODUCTION, // 仅在生产环境启用
        /** 是否在控制台输出压缩结果 */
        verbose: true,
      }),
]

压缩后:

image.png

提升了两分耶!可能是因为该系统总览页有一张背景图,导致lcp长。图片压缩后,lcp减少0.3s。

总结

嗯....吭哧吭哧改了半天,提了4️⃣分。我找找理由吧。我觉得是其一是vue+vite在性能方面已经做的很好了,无需进一步做什么优化;其二我们的项目本身就比较小,优化空间少。在web前端性能优化层面除了上面说的一些大的点,还有就是开发中一些小的点,比如防抖、v-for加key等等一系列吧。
就到这啦,后续会不断完善,欢迎大家批评指正!