常见的 Web 项目性能优化方法有哪些?也适用于首页
✅ 一、总结:Web 性能优化 checklist(速查表 📋)
优化方向 | 常见手段 |
---|---|
资源加载优化 | 压缩代码/图片、CDN、合并文件、按需加载、Tree Shaking |
网络与缓存 | 强缓存 / 协商缓存、HTTP/2、减少请求数、Gzip/Brotli |
渲染性能 | 减少重绘回流、使用 transform/opacity、避免长任务 |
首屏优化 | SSR/SSG、预加载、内联关键 CSS、骨架屏 |
交互优化 | 优化 TTI、减少阻塞 JS、Web Workers |
框架优化 | React.memo、useMemo、路由懒加载、组件拆分 |
代码打包 | 代码分割、Tree Shaking、分析 Bundle、减少依赖 |
缓存策略 | Service Worker、长期缓存、immutable |
监控与指标 | Lighthouse、Web Vitals、RUM、持续优化 |
✅ 一、为什么 Web 性能优化至关重要?
性能直接影响:
🚀 用户体验(页面快不快、交互是否流畅、是否卡顿)
📈 业务转化率(页面越慢,用户越容易离开,尤其是移动端)
🏆 SEO 排名(Google 等搜索引擎将 Core Web Vitals 作为排名因素)
⚡ 首屏加载速度、运行时性能、可交互性 等关键指标
✅ 二、Web 性能优化:整体分类
🧩 一、加载性能优化(Loading Performance)
让页面 更快加载出来、更快可用
1. 减少资源体积
✅ 压缩代码:JS / CSS / HTML(Terser(TerserPlugin)、css-minimizer-webpack-plugin、HtmlWebpackPlugin)
默认情况下,是压缩所有打包后的代码,但通过配置,我们可以控制是否压缩某些模块、是否删除 console、是否保留注释、是否混淆变量名等,也就是说,可以实现“部分压缩”或“精细化控制”。同样,CSS 和 HTML 也有相应的压缩插件与配置项,可以根据需求灵活启用或调整压缩策略。
“Webpack 默认在 production 模式下会使用 TerserPlugin 压缩代码,但为了更好地控制压缩行为(比如删除 console、保留版权注释、优化构建速度等),我们通常会手动配置 TerserPlugin,调整 terserOptions 和并行策略等。”
当你设置mode:producition,Webpack 4+ 会 自动启用代码压缩,底层使用的是:
👉 TerserPlugin(Webpack 5 默认),
它是对代码进行 压缩(删除空格/注释/换行)、混淆(mangling)、删除死代码 的工具
我手动配置过 TerserPlugin,主要优化点包括:
开启
parallel: true
,利用多核 CPU 加速压缩配置
drop_console: true
,删除 console.log 调用,减少生产环境冗余代码配置
drop_debugger: true
,删除 debugger 语句调整
format.comments
为false
或正则,控制是否保留版权注释通过
terserOptions.mangle
控制变量名混淆行为通过
exclude
排除某些不需要压缩的库
Terser 的压缩和混淆操作是 语法层面的优化,不会影响代码逻辑
实际项目中,压缩代码通常可以让 JS 文件体积减少 30% ~ 70%,是提升页面加载速度最直接有效的方式之一。”
使用
css-minimizer-webpack-plugin
,删除空白、注释,优化选择器HtmlWebpackPlugin 配置 minify 压缩 HTML,减小文件体积,提升加载速度。
这俩需要配置 不是自带的
你做了代码压缩,那如何保证压缩后的代码还能正常运行?如何调试?如何处理 Source Map?
翻译:你考虑过压缩带来的副作用和工程化问题吗?
“压缩代码可能会导致变量名不可读、删除注释、删除 console 等,但一般不会影响代码逻辑,因为 Terser 是语法层面的优化。
但需要注意:
开发环境 一般不压缩或使用 source map,便于调试
生产环境 可以配置
sourceMap: true
,生成对应的.map
文件,方便线上排查问题如果使用 Terser 删除了 console 或 debugger,要确保不影响调试和错误追踪
我通常会在生产构建时开启压缩,但通过
drop_console: false
或环境变量控制是否删除调试代码
✅ 压缩图片:使用
image-webpack-loader
或 CDN 自动压缩✅ 移除未使用的代码(Tree Shaking,尤其在 ES Module / Webpack 下)
原理上:
ES Module 的导入导出是静态的(编译时可确定),Webpack 或 Rollup 可以分析哪些 export 被使用,哪些没有被使用
在生产模式下(
mode: 'production'
),Webpack 会结合 TerserPlugin,在压缩时将未被引用的导出代码删除
但需要注意:
必须使用 ES Module 格式(import/export),而不是 CommonJS(require/module.exports)
模块本身要支持 Tree Shaking(比如 lodash-es,而不是 lodash)
在 Webpack 中要关闭不必要的副作用,比如在 package.json 中设置
"sideEffects": false
或指定有副作用的文件
所以,Tree Shaking 是一种非常有效的减小 bundle 体积的手段,尤其对大型第三方库引入很有帮助。
✅ 按需加载(代码分割,动态
import()
)“动态
import()
是 ES2020 提供的一个 语法,用于异步加载模块,它返回一个 Promise,当模块加载完成后 resolve。在 Webpack 中,使用动态
import()
会触发 代码分割(Code Splitting),Webpack 会把这个模块单独打包成一个 chunk,只有在调用 import() 时才会去加载这个文件。常见使用场景包括:
路由懒加载:比如 React Router / Vue Router 中按路由异步加载页面组件
组件懒加载:比如某个弹窗组件、复杂图表,只有用户点击时才加载
功能模块按需加载:比如某些用户才用到的功能,动态导入
✅你做了按需加载,那如何确保拆分的 chunk 是合理的?如何分析打包结果?
webpack-bundle-analyzer:可视化查看打包后的模块分布、chunk 大小
“它们都是优化前端代码体积与加载性能的重要手段,通常会 组合使用:
Tree Shaking:移除未使用的代码,让打包结果更小(主要针对 ES Module 的库和工具)
Code Splitting(代码分割):将代码拆分成多个 chunk,按需加载或公共提取
动态 import():是实现按需加载的一种具体方式,触发 Webpack 自动进行代码分割
比如:
我会先用 Tree Shaking 移除无用导出
然后通过 SplitChunksPlugin 提取公共依赖
最后对一些非首屏组件或路由使用动态 import() 实现懒加载
这样组合起来,可以最大化减少首屏资源大小,提升加载性能与用户体验。”
2. 减少网络请求
// babel.config.js
plugins: [
['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }]
]
然后代码中这样引入
import { Button } from 'antd'; // 只引入 Button 组件及其样式
注意事项:
适合放到 CDN 上的资源包括:
✅ 合并文件(如 CSS / JS 合并,但注意 HTTP/2 下不一定需要)
在 HTTP/1.1 环境下,将多个 JS / CSS 文件合并为一个,减少浏览器发起的请求数量,提升加载效率;但在 HTTP/2 环境下,由于支持多路复用,可以适当减少合并,优先考虑按需加载和缓存优化。
“合并文件是通过构建工具将多个 JavaScript 或 CSS 文件合并为一个或少量文件,以减少浏览器发起的网络请求数量,从而提升页面加载性能,尤其在 HTTP/1.1 环境下非常有效。
在现代前端项目中,我通常使用 Webpack 或 Vite 等工具自动完成合并:比如将多个 JS 模块打包成一个
bundle.js
,或者通过MiniCssExtractPlugin
将多个 CSS 文件合并为styles.css
。对于 CSS,我也会使用
style-loader
或提取插件来控制是否内联或合并输出。是否合并文件,还需要根据当前是 HTTP/1.1 还是 HTTP/2 环境、是否需要按需加载、缓存策略等综合考虑,而不是盲目合并。”✅ 减少第三方库的引入,按需引入(如 lodash-es、antd 按需加载)
现在我们推荐使用 lodash-es(支持 ES Module) + 按需引入:
import debounce from 'lodash-es/debounce'; // 只引入需要的函数
使用 babel-plugin-import(配合 babel 配置)
✅ 使用 CDN 加速静态资源(JS、CSS、字体、图片等)
CDN(Content Delivery Network,内容分发网络)是一组分布在全球各地的服务器节点,它通过 就近原则 将静态资源(如 JS、CSS、图片、字体)缓存并分发到离用户最近的节点,从而:
降低网络延迟
提高资源加载速度
减轻源站(你的服务器)压力
JS / CSS / 字体 / 图片 / 视频等静态资源
不经常变化的公共库(比如 React、Vue、Lodash 的 CDN 版本,可通过
<script>
引入)CDN 资源要有 稳定的 URL 且支持长期缓存(如 Cache-Control: max-age=31536000)
如果使用 CDN 引入第三方库(如 React 的 CDN 版本),要注意 全局变量冲突、版本管理、与打包工具的配合
对于 动态内容、用户私有数据、API 请求,CDN 并不适用
要合理设置 缓存策略、回源策略、HTTPS 支持等
3. 利用浏览器缓存
✅ 强缓存:
Cache-Control: max-age=31536000
、immutable、
“
immutable
是Cache-Control
的一个指令,表示 这个资源在缓存有效期内永远不会改变,即使过期了,浏览器也 不会发送任何验证请求(如 304),直接使用本地缓存。Cache-Control: max-age=31536000, immutable
⚠️ 注意: 只能用于 内容确定不会变更的资源,如果资源内容变了但文件名没变,使用 immutable 会导致用户一直拿到旧文件。
✅ 协商缓存:
Last-Modified
/ETag
,返回 304✅ 对静态资源设置长期缓存 + 文件名 hash(如
main.abc123.js
)
4. 优化关键渲染路径(渲染路径,关于url输入到省城页面流程)
✅ 内联关键 CSS
首屏渲染所必需的 CSS 样式
✅ 延迟加载非关键 JS(
defer
/async
或动态 import)✅ 避免阻塞渲染的资源为什么它们会阻塞渲染?
JS 阻塞: 浏览器为了保证脚本执行顺序和 DOM 操作安全,默认会 先解析并执行 JS,再继续解析 HTML
CSS 阻塞: CSSOM 构建是渲染树的必要前提,浏览器会等待 CSS 加载与解析完成,才进行布局与绘制
5. 使用 HTTP/2 或 HTTP/3
✅ 多路复用、头部压缩、更快的资源加载
🧩 二、渲染性能优化(Rendering Performance)
让页面 渲染更流畅,动画更顺滑,交互更跟手
1. 提升 FPS(每秒帧数)
✅ 避免长任务(Long Tasks,单个 JS 任务不要超过 50ms) ???
✅ 减少不必要的重绘(Repaint)与回流(Reflow) 怎么减少??
✅ 使用
requestAnimationFrame
优化动画。怎么整?✅ 使用 CSS
transform
和opacity
实现动画(GPU 加速)
2. 减少 DOM 操作
✅ 批量更新 DOM,避免频繁操作 ????
✅ 使用文档片段(DocumentFragment)或虚拟 DOM(如 React/Vue)
3. 虚拟列表(Virtual List)
✅ 只渲染可视区域内的列表项,用于超长列表(如 10000 条数据)
4. 避免强制同步布局(Layout Thrashing)
✅ 不要在 JS 中连续读写布局属性(如 offsetTop、scrollHeight 等)
🧩 三、前端框架优化(React / Vue )
针对具体框架的优化手段
1. React 优化
✅ 使用
React.memo
、useMemo
、useCallback
避免不必要的渲染✅ 组件拆分,遵循单一职责
✅ 使用懒加载路由(React.lazy + Suspense)
✅ 避免在渲染中直接进行复杂计算,抽离到
useEffect
或useMemo
✅ 合理使用 Context,避免全局状态频繁触发更新
2. Vue 优化
✅ 使用
v-once
、v-memo
、computed
、watchEffect
优化渲染✅ 合理拆分组件,避免大组件频繁 diff
✅ 使用异步组件 / 路由懒加载
✅ 避免不必要的响应式数据
3. 通用优化
✅ 减少不必要的重新渲染
✅ 列表项使用唯一的
key
✅ 避免深层嵌套的组件与状态
🧩 四、首屏 & 交互性能优化
让用户 更快看到内容、更快可以操作
1. 优化首屏加载(FCP / LCP)
✅ 服务端渲染(SSR)或静态生成(SSG):Next.js / Nuxt.js / Gatsby
✅ 预加载关键资源:
<link rel="preload">
✅ 骨架屏(Skeleton Screen)提升感知速度
✅ 内联关键资源(如首屏 CSS / 小图片 Base64)
2. 提升可交互时间(TTI)
✅ 减少长任务,优化 JS 执行时间
✅ 延迟加载非关键 JS 和第三方库
✅ 使用 Web Workers 处理复杂计算,不阻塞主线程
3. 优化 LCP(最大内容绘制)
✅ 优化首屏关键内容(如图片、标题、Banner)的加载
✅ 图片使用现代格式 + 压缩 + CDN
✅ 预加载关键图片 / 字体
✅ 服务端快速返回首屏 HTML
🧩 五、缓存优化
让用户下次访问 更快、更省流量
1. 强缓存 vs 协商缓存
✅ 静态资源:强缓存(
max-age
+immutable
)✅ 动态内容:协商缓存(
Last-Modified
/ETag
)
2. Service Worker 缓存(PWA)
✅ 离线可用、资源缓存、请求拦截、更新策略
✅ 实现离线缓存、后台同步、消息推送
3. 浏览器缓存策略
✅ 对 JS、CSS、图片等设置长期缓存
✅ HTML 文件:可以设置
no-cache
或短期缓存
🧩 六、代码 & 打包优化
让打包结果 更小、更快、更合理
1. Tree Shaking
✅ 删除未使用的代码(适用于 ES Module,如 webpack / rollup)
2. Code Splitting(代码分割)
✅ 按路由拆分、按功能拆分,动态
import()
3. Bundle / 包分析
✅ 使用
webpack-bundle-analyzer
查看打包内容,优化冗余依赖
4. 减少依赖体积
✅ 按需引入第三方库(如 lodash-es、antd、moment 等)
✅ 移除未使用的 npm 包
🧩 七、监控与持续优化
没有监控的优化,就无法持续改进
1. 性能监控工具
✅ Lighthouse(Chrome 插件 / CLI)
✅ Chrome DevTools(Performance / Network / Lighthouse)
2. Core Web Vitals 指标优化
✅ LCP(最大内容绘制)< 2.5s
✅ FID(首次输入延迟)< 100ms
✅ CLS(累积布局偏移)< 0.1
✅ FCP(首次内容绘制)< 1.8s
✅ TTI(可交互时间)< 3.5s