前端性能优化

本文最后更新于:2022年5月7日 上午

🏆 记录前端的性能优化方案

资源缓存

资源缓存一般用户缓存静态资源文件,例如: 图片,js文件,css文件等

强缓存

简单理解

  • 如果没有强缓存,则直接向服务器发送请求(类似第一次请求)

  • 如果命中了强缓存,且缓存没有失效,则直接从缓存中取到静态资源

  • 如果命中了强缓存,但是缓存已失效,则进入到协商缓存

优先级权重

Expires<Cache-Control<Pragma

强缓存是在客户端向服务端发送get请求时,服务端向客户端响应式,请求头上的ExpiresCache-Control 或者 Pragma 来设置的

强缓存又分为 Disk-Cache (硬盘缓存) 和 Memory-Cache(内存缓存),存放位置是由浏览器来决定的。

  • Expires (http 1.0)&#x20;

    设置的是指定过期时间,客户端准备向服务端发请求的时,会先用本地时间和这个过期时间对比,超过则重新向服务端发请求,这里可能会存在客户端和服务端时间不一致的情况

  • Cache-Control (http 1.1) (优先级高)&#x20;

    存的是一个过期的秒,客户端准备向服务端发请求的时,会先判断是否超过这个间隔,如果超过,则重新向服务端发请求。

    当与 Expires 同时存在时,Cache-Control优先级高

  • Pragma&#x20;

    只有一个值:no-cache (优先级最高)

    当与 ExpiresCache-Control 同时存在时,Pragma优先级最高

协商缓存

简单理解

  • 协商缓存生效,服务端返回 304

  • 协商缓存失效,服务端返回200和请求结果

当强缓存没有命中时,则会到协商缓存,协商缓存每次发请求时会带上 last-modified 或者 etag 请求头与服务端协商是否启用缓存,如果服务器返回 304 状态码,则浏览器会从缓存中读取资源

  • last-modified/ if-Modified-Since (http 1.0)

    记录的是该文件最后一次修改该文件的时间,最小单位为秒

    当客户端第一次请求服务端的时候,服务端会返回 last-modified,客户端第二次向服务端发起请求的时候,会将该值作为请求头 if-Modified-Since 的值去请求服务端,服务端拿到这个值后会和文件的最后一次修改时间对比,如果一致,则命中协商缓存,返回 304 ,浏览器从缓存中加载资源

  • ETag / if-None-Match (http 1.1) (优先级高)

    记录的是该文件的一串 hash值,每次文件发生修改,都会计算出一个新的 hash 值。

    当客户端第一次请求服务端的时候,服务端会返回 ETag,客户端第二次向服务端发起请求的时候,会将该值作为请求头 if-None-Match 的值去请求服务端,服务端拿到这个值后会和文件的最后一次的****值对比,如果一致,则命中协商缓存,返回 304 ,浏览器从缓存中加载资源

Etag 相对于 last-modified 解决了什么问题:

当文件在1秒内发生修改,last-modified 会错误的返回 304,当文件发生改变,但是文件内容没有发生修改的时候(如:新增了一行,又把这一行删除),last-modified 也会错误的返回304

可参考 图解HTTP缓存

数据缓存

数据缓存一般用于在数据不频繁变动的情况下,我们可以从缓存中读取,减少服务端的压力

常见的三种数据缓存的方案

  • localStorage

    一般用户自定义设置过期时间

    存数据的同时需要存一个过期时间,第二次发请求的时候先从缓存中读,如果读到且未过期则使用缓存数据

  • sesstionStorage

    当前窗口关闭时,缓存失效,因为 sesstionStorage 只会在窗口打开到关闭存储,所以当窗口关闭时,数据也会清空&#x20;

  • vuex/redux

    单页面 spa应用一般用于,当页面刷新之前,可以做自定义缓存策略

dns 解析优化

dns 解析一般在 20-120 ms之间,所以当我们一个应用中需要解析的域名过多的话,其实也会对性能有一定的影响,但是我们实际开发中,通常都是做的多服务器部署,把不同的资源放到不同的服务器上如:静态资源服务器,接口服务器等,因为多服务器部署有很多好处

那我们如果一个应用需要 dns 解析的域名过多可以怎么办呢,京东官网就是一个很好的示例,可以在 里面添加 dns 预解析

<link rel="dns-prefetch" href="//static.360buyimg.com">
<link rel="dns-prefetch" href="//misc.360buyimg.com">

前端层面优化

  • 减少请求次数和请求大小 (合理的对文件进行切割)

  • 静态资源文件压缩 (webpack层面对 js,css代码压缩等)

  • 启用 gizp

  • 大批量数据分批请求 (分页或上拉加载更多,避免出现一次性返回10万条数据该怎么处理的问题😉)

  • 字体图片和 svg

  • 雪碧图/精灵图

  • 小图片使用 base64,或者较为重要的图片也使用 base64

  • 图片懒加载

  • 资源懒加载 (路由懒加载)

  • 小图片使用 base64,或者较为重要的图片也使用 base64

  • 较为重要的图片也可以使用 preload<link rel="preload" as="image" href="https://xxx.com/png" />

  • 图片懒加载

  • 资源懒加载 (路由懒加载)

  • 公共组件按需引入(尽量不使用 require 引入模块)

  • 使用 Resource Hints 对资源进行 prefetch

  • 较大的图片根据不同设备来渲染(CDN配合业务具体实现:使用 img 标签 srcset/sizes 属性和 picutre 标签实现响应式图片,具体可参考文档)

  • 尽可能不写内联 css 样式(如果项目需要兼容不同端时,内联的 px 会成为致命的问题)

  • 静态资源部署到 CDN, CDN预热:提前将资源分发到各个节点,避免太多流量打到源站(看具体业务场景)

Vue 优化

  • 生产模式关闭 souceMap

  • 路由懒加载

Webpack 优化

  • 第三方库使用 CDN &#x20;

  • 合理的使用 splitchunks 进行文件分割,合理的调整阈值

  • 启用tree shaking(摇树) webpack 4 版本以上 production 模式 默认开启

  • 首屏关键 css 进行内联样式设置(内容固定(使用脱离文档流固定宽高),不抖动),可以使用 critters