当前位置: 首页 > news >正文

常见的 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=31536000immutable、

  • immutable是 Cache-Control的一个指令,表示 ​​这个资源在缓存有效期内永远不会改变​​,即使过期了,浏览器也 ​​不会发送任何验证请求(如 304)​​,直接使用本地缓存。

    Cache-Control: max-age=31536000, immutable

    ⚠️ ​​注意:​​ 只能用于 ​​内容确定不会变更的资源​​,如果资源内容变了但文件名没变,使用 immutable 会导致用户一直拿到旧文件。

  • ✅ 协商缓存:Last-ModifiedETag,返回 304

  • ✅ 对静态资源设置长期缓存 + 文件名 hash(如 main.abc123.js

4. ​​优化关键渲染路径(渲染路径,关于url输入到省城页面流程)
  • ✅ 内联关键 CSS

  • 首屏渲染所必需的 CSS 样式​

  • ✅ 延迟加载非关键 JS(deferasync或动态 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.memouseMemouseCallback避免不必要的渲染

  • ✅ 组件拆分,遵循单一职责

  • ✅ 使用懒加载路由(React.lazy + Suspense)

  • ✅ 避免在渲染中直接进行复杂计算,抽离到 useEffect或 useMemo

  • ✅ 合理使用 Context,避免全局状态频繁触发更新

2. ​​Vue 优化​
  • ✅ 使用 v-oncev-memocomputedwatchEffect优化渲染

  • ✅ 合理拆分组件,避免大组件频繁 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-ageimmutable

  • ✅ 动态内容:协商缓存(Last-ModifiedETag

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

http://www.dtcms.com/a/394930.html

相关文章:

  • Qt QMainWindow类深度解析:主窗口框架的核心实现
  • 知识图谱对自然语言处理深层语义分析的革命性影响与启示
  • 内部标识符
  • 计算机网络2
  • 计算机视觉(opencv)实战三十二——CascadeClassifier 人脸微笑检测(摄像头)
  • MyBatis-Plus 全方位深度指南:从入门到精通
  • PyTorch 神经网络工具箱:从组件到基础工具,搭建网络的入门钥匙
  • 分布式专题——18 Zookeeper选举Leader源码剖析
  • JVM 调优在分布式场景下的特殊策略:从集群 GC 分析到 OOM 排查实战(二)
  • 基于OpenEuler部署kafka消息队列
  • Flink TCP Channel复用:NettyServer、NettyProtocol详解
  • Sass和Less的区别【前端】
  • Kotlin互斥锁Mutex协程withLock实现同步
  • Seedream 4.0 测评|AI 人生重开:从极速创作到叙事实践
  • vscode clangd 保姆教程
  • MySQL时间戳转换
  • 【Spark+Hive+hadoop】基于spark+hadoop基于大数据的人口普查收入数据分析与可视化系统
  • 分布式专题——17 ZooKeeper经典应用场景实战(下)
  • TDengine 2.6 taosdump数据导出备份 导入恢复
  • 探索 Yjs 协同应用场景 - 分布式撤销管理
  • 【软考中级 - 软件设计师 - 基础知识】数据结构之栈与队列​
  • LeetCode 385 迷你语法分析器 Swift 题解:从字符串到嵌套数据结构的解析过程
  • windows系统使用sdkman管理java的jdk版本,WSL和Git Bash哪个更能方便管理jdk版本
  • 生产环境K8S的etcd备份脚本
  • Mac电脑多平台Git账号配置
  • Etcd详解:Kubernetes的大脑与记忆库
  • 深刻理解PyTorch中RNN(循环神经网络)的output和hn
  • 大模型如何赋能写作:从创作到 MCP 自动发布的全链路解析
  • C++设计模式之创建型模式:工厂方法模式(Factory Method)
  • 传输层协议——UDP/TCP