# 前端性能优化方案

# 1. 减少耗时

# 1.1 缓存策略

合理利用缓存可以显著减少资源加载时间:

  • 浏览器缓存:通过设置 Expires 和 Cache-Control 实现强缓存
  • 协商缓存:通过设置 Last-Modified/If-Modified-Since 和 ETag/If-None-Match 实现
  • 服务端缓存:利用Redis、Memcached等技术缓存计算结果
  • CDN缓存:将静态资源分发到全球节点,提升用户访问速度
  • DNS缓存:预解析(dns-prefetch)、本地、运营商DNS查询缓存

# 1.2 减少请求耗时

从请求次数和请求大小两个维度优化:

  • 减少请求次数

    • 合并资源(CSS Sprites、JS/CSS文件合并)
    • 使用缓存避免重复请求
    • 服务端开启Gzip压缩
    • 使用HTTP/2多路复用技术
  • 减少请求大小

    • 开启Gzip/Brotli压缩
    • 使用更高效的图片格式(WebP、AVIF)
    • Tree-shaking清除未使用代码
    • 代码压缩和混淆

# 2. 减少资源大小

# 2.1 Gzip/Brotli压缩

  • 服务端开启Gzip/Brotli压缩可以有效减少传输资源的大小 40%
  • webpack插件:compression-webpack-plugin
  • Nginx配置示例:
  gzip on;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
1
2

# 2.2 Tree-shaking

  • Tree-shaking 是一种通过清除多余代码方式来优化项目打包体积的技术

  • 基于ES6的静态引用,Tree-shaking通过扫描所有ES6的export,找出被import的内容并添加到最终代码中

  • webpack4中只需要将mode设置为production就会默认启动Tree-shaking

  • 需要注意:只有ES6模块语法才能被Tree-shaking优化,CommonJS模块无法被优化

  • 打包 针对图片进行压缩

  • 打包 按需加载,减少无用包的引入

  • 减小第三方库的大小,如Moment.js/lodash等,使用轻量级别替代方案或者自己重新实现 dayjs

# 3. CSS优化

# 3.1 避免使用CSS表达式

CSS表达式会频繁执行,影响页面性能:

/* bad */
background-color: expression((new Date()).getHours()%2?"#fff":"#000");

/* good */
background-color: #fff;
1
2
3
4
5

# 3.2 使用link代替@import

  • link属于HTML标签,@import属于CSS范畴
  • link最大限度支持并行下载,@import会使得页面在加载时增加额外的延迟
  • link可以通过rel="alternate stylesheet"指定候选样式
  • 浏览器对link支持早于@import

# 3.3 CSS文件优化

  • 压缩CSS文件:移除空格、注释和不必要的字符
  • 合并CSS文件:减少HTTP请求数量
  • 使用CSS Sprites:合并小图标图片
  • 避免CSS选择器嵌套过深:减少CSS引擎查找元素的时间(读取选择器,遵循从右到左读取。避免通配符,最大化样式继承,少用标签选择器,减少过深嵌套)
  • 使用CSS3硬件加速:利用GPU提升动画性能
  • 使用Flex布局:使用新版的 flex 进行布局比我们用的一些“老式”方法性能更好

# 4. JavaScript优化

# 4.1 JS文件位置

  • JS会阻塞页面渲染,将JS文件放在body底部可以优先渲染页面内容
  • 使用async/defer属性异步加载脚本:
    • async:立即下载脚本,下载完立即执行(不保证执行顺序)
    • defer:立即下载脚本,等待DOM解析完成后按顺序执行

# 4.2 外部JS文件

  • 外部JS文件可以被浏览器缓存,减少重复下载
  • 外部JS文件可以被多个页面共享
  • 合理拆分JS文件,避免单个文件过大

# 4.3 减少DOM访问

  • 缓存DOM元素:重复访问的DOM元素应该缓存到局部变量中
  • 减少DOM操作:合并多次DOM操作,减少重排和重绘
  • 使用DocumentFragment批量操作DOM
  • 避免在循环中操作DOM

# 4.4 代码优化

  • 变量优化:使用局部变量而非全局变量,减少作用域链查找
  • 循环优化:减少循环内重复计算,使用缓存变量
  • 事件优化:使用事件委托减少事件监听器数量
  • 防抖节流:对频繁触发的事件使用防抖节流优化

# 5. 图片优化

# 5.1 压缩图片

  • 使用工具压缩图片,减少图片大小
  • 工具:tinypng、imagemin-webpack-plugin、squoosh
  • 在线工具:TinyPNG、智图

# 5.2 使用CSS Sprites

  • 将多个小图片合并成一张大图片,减少HTTP请求次数
  • 注意维护成本,适用于不经常变动的小图标

# 5.3 使用更高效的图片格式

  • WebP格式:相比JPEG和PNG,WebP可以提供更好的压缩率和质量
  • AVIF格式:新一代图像格式,压缩率比WebP更好
  • SVG格式:对于简单的图标和图形,SVG可以提供无损缩放和较小的文件大小

# 5.4 图片懒加载

  • 对于页面中不需要立即显示的图片,可以使用懒加载技术,当用户滚动到图片位置时再加载图片
  • 实现原理:监听滚动事件,判断图片是否进入可视区域,如果进入则加载图片
  • 现代浏览器原生支持:使用loading="lazy"属性

# 5.5 响应式图片

  • 使用<picture>元素和srcset属性实现响应式图片
  • 根据设备屏幕密度和尺寸加载不同分辨率的图片
  • 代码示例:
    <picture>
      <source media="(min-width: 768px)" srcset="large.jpg">
      <source media="(min-width: 480px)" srcset="medium.jpg">
      <img src="small.jpg" alt="响应式图片">
    </picture>
    
    1
    2
    3
    4
    5

# 6. DOM优化

# 6.1 合并修改

  • 合并多次DOM修改,减少重排和重绘
  • 使用DocumentFragment批量操作DOM
  • 使用CSS类名批量修改样式,而非逐个修改style属性
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来

# 6.2 虚拟列表

  • 对于大量数据的列表,可以使用虚拟列表技术,只渲染可视区域的列表项,减少DOM节点数量
  • 常用库:react-window、react-virtualized、vue-virtual-scroll-list

# 6.3 事件委托

  • 利用事件冒泡机制,将事件监听器绑定到父元素上,减少事件监听器数量
  • 适用于动态添加的元素,无需为每个元素单独绑定事件
  • 使用函数节流(throttle)或函数防抖(debounce),限制某一个方法的频繁触发

# 6.4 其他DOM优化技巧

  • 减少DOM节点数量:避免不必要的嵌套和冗余元素
  • 优化CSS选择器:避免使用低效的选择器(如属性选择器、通配符选择器)
  • 使用requestAnimationFrame:将DOM操作推迟到下一帧执行,避免阻塞渲染
  • 避免强制同步布局:不要在修改DOM后立即读取布局属性
  • CSS是阻塞的资源: 尽早(CSS放在head里)和尽快(启用CDN)。浏览器在构建CSSOM的过程中,不会渲染任何已处理的内容,即便DOM已经解析完毕了,防止浏览器有可能还未下载和解析到CSS就已经开始渲染页面
  • JS阻塞: 加载或者执行JS时会阻塞对标签的解析,也就是阻塞了DOM 树的形成,只有等到JS执行完毕,浏览器才会继续解析标签(因为加载的 JS 中可能会创建,删除节点)
  • defer并行下载: 不会阻塞 HTML 解析,等到 DOM 生成完毕且 script 加载完毕再执行 JS
  • **async并行下载:表示异步执行引入的 JS,加载时不会阻塞 HTML解析,但是加载完成后立马执行,此时仍然会阻塞 load 事件
标签 js执行顺序 阻塞解析HTML
scipt 在HTML中的顺序 阻塞
scipt defer 在HTML中的顺序 不阻塞解析
scipt async 网络请求返回顺序 可能阻塞,也可能不阻塞,取决于什么时候下载完成

详细区别 (opens new window)

# 7. 浏览器渲染优化

# 7.1 关键渲染路径优化

  • 减少关键资源数量:内联关键CSS,延迟加载非关键资源
  • 优化关键资源大小:压缩CSS、JavaScript和HTML
  • 减少关键路径长度:减少资源请求的依赖链

# 7.2 CSS优化

  • 内联关键CSS:将首屏渲染必需的CSS内联到HTML中
  • 避免CSS阻塞渲染:使用media属性标记非关键CSS
    <link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
    
    1
  • 避免CSS选择器嵌套过深:减少CSS引擎查找元素的时间

# 7.3 图片优化

  • 图片懒加载:使用loading="lazy"属性延迟加载非关键图片

# 8. 其他优化

# 8.1 使用Web Worker

  • 将耗时的计算任务放到web worker中执行,避免阻塞主线程
  • 适用于图像处理、大数据计算等场景
  • 注意:web worker中无法访问DOM,只能通过postMessage通信

# 8.2 使用骨架屏

  • 在页面内容加载完成前,显示骨架屏,提升用户体验
  • 骨架屏应该与实际内容布局保持一致
  • 可以使用CSS动画实现加载效果

# 8.3 服务端渲染(SSR)

  • 使用服务端渲染可以减少首屏渲染时间,提升SEO效果
  • 常用框架:Next.js、Nuxt.js
  • 注意:会增加服务端压力,需要权衡利弊

# 8.4 预加载和预渲染

  • DNS预解析:提前解析域名,减少DNS查询时间
  • 预加载关键资源:使用<link rel="preload">提前加载关键资源
  • 预渲染:提前渲染页面内容,减少白屏时间

# 8.5 PWA优化

  • 使用Service Worker实现离线缓存
  • 添加Web App Manifest实现添加到主屏幕功能
  • 使用Push API实现消息推送
Last Updated: 9/16/2025, 2:58:59 PM