XingYun blog
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具

XingYun

冲!
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具
  • vue-cli打包配置
  • 前端打包文件的缓存机制
    • NPM是什么
    • 工程化
    XingYun
    2021-11-22
    目录
    强缓存和协商缓存
    前端缓存方案
    静态资源的 hash 配置
    node 后端设置

    前端打包文件的缓存机制

    # 强缓存和协商缓存

    一般习惯将缓存分为强缓存和协商缓存两种。两者的主要区别是使用本地缓存的时候,是否需要向服务器验证本地缓存是否依旧有效。顾名思义,协商缓存,就是需要和服务器进行协商,最终确定是否使用本地缓存。

    # 强缓存

    我们知道,强缓存主要是通过 http 请求头中的 Cache-Control 和 Expire 两个字段控制。Expire 是 HTTP1.0 标准下的字段,在这里我们可以忽略。我们重点来讨论的 Cache-Control 这个字段。

    一般,我们会设置 Cache-Control 的值为“public, max-age=xxx”,表示在 xxx 秒内再次访问该资源,均使用本地的缓存,不再向服务器发起请求。

    显而易见,如果在 xxx 秒内,服务器上面的资源更新了,客户端在没有强制刷新的情况下,看到的内容还是旧的。如果说你不着急,可以接受这样的,那是不是完美?然而,很多时候不是你想的那么简单的,如果发布新版本的时候,后台接口也同步更新了,那就 gg 了。有缓存的用户还在使用旧接口,而那个接口已经被后台干掉了。怎么办?

    # 协商缓存

    协商缓存最大的问题就是每次都要向服务器验证一下缓存的有效性,似乎看起来很省事,不管那么多,你都要问一下我是否有效。但是,对于一个有追求的码农,这是不能接受的。每次都去请求服务器,那要缓存还有什么意义。。

    # 前端缓存方案

    缓存的意义就在于减少请求,更多地使用本地的资源,给用户更好的体验的同时,也减轻服务器压力。所以,最佳实践,就应该是尽可能命中强缓存,同时,能在更新版本的时候让客户端的缓存失效。

    所以问题是在强缓存前提下,更新版本之后,如何让用户第一时间使用最新的资源文件呢?

    前端页面的入口 index.html 不使用缓存或者使用协商缓存。, 静态资源使用强缓存,更新版本的时候,把静态资源的路径都改了,这样,就相当于第一次访问这些资源,就不会存在缓存的问题了。

    下图为生产环境的网络请求

    我们定下一个大概方案

    HTML:使用协商缓存。
    CSS&JS&图片:使用强缓存,文件命名带上 hash 值。

    # 静态资源的 hash 配置

    上图可以看到每个静态资源文件名中间都加上了 hash 值,如果每次更新版本都要手动一个一个去修改文件名,那也太让人难受了

    幸运的是,webpack 可以让我们在打包的时候,在文件的命名自动加上 hash 值。

    # webpack 三种哈希计算方式

    webpack 给我们提供了三种哈希值计算方式,分别是 hash、chunkhash 和 contenthash。那么这三者有什么区别呢?

    hash:跟整个项目的构建相关,构建生成的文件 hash 值都是一样的,只要项目里有文件更改,整个项目构建的 hash 值都会更改。
    chunkhash:根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的 hash 值。
    contenthash:由文件内容产生的 hash 值,内容不同产生的 contenthash 值也不一样。

    vue-cli 默认选择 chunkhash, vue-cli 制作的 Webpack 配置。它们已经被很好地优化了,如果你对 webpack 不太熟悉,不建议对它做修改

    // vue-cli默认配置
    module.exports = {
      configureWebpack: (config) => {
        return {
          optimization: {
            splitChunks: {
              chunks: 'async',
              minSize: 30000,
              maxSize: 0,
              minChunks: 1,
              maxAsyncRequests: 6,
              maxInitialRequests: 4,
              automaticNameDelimiter: '~',
              cacheGroups: {
                vendors: {
                  name: `chunk-vendors`,
                  test: /[\\/]node_modules[\\/]/,
                  priority: -10,
                  chunks: 'initial'
                },
                common: {
                  name: `chunk-common`,
                  minChunks: 2,
                  priority: -20,
                  chunks: 'initial',
                  reuseExistingChunk: true
                }
              }
            }
          }
        }
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33

    显然,我们一般不会使用第一种。改了一个文件,打包之后,其他文件的 hash 都变了,缓存自然都失效了。

    chunkhash 按块计算 hash,只有模块变化了 才会重新计算 hash 值,强缓存命中高,在工作中的运用最广。

    但是这样又有一个问题,因为我们是将样式作为模块 import 到 JS 文件中的,所以它们的 chunkhash 是一致的,如 test.js 和 var.css。

    这样就会有个问题,只要对应 css 或则 js 改变,与其关联的文件 hash 值也会改变,但其内容并没有改变呢,所以没有达到缓存意义。

    所以 contenthash 的用途随之而来

    contenthash 是针对文件内容级别的,只有你自己模块的内容变了,那么 hash 值才改变,所以我们可以通过 contenthash 解决上诉问题

    # node 后端设置

    上文说明了前端是如何进行打包,后端也需要配合做一些设置

    浏览器是根据响应头的相关字段来决定缓存的方案的。所以,后端的关键就在于,根据不同的请求返回对应的缓存字段。

    以 nodejs 为例,如果需要浏览器强缓存,我们可以这样设置:

    静态资源采用强缓存,可以这样设置:

    res.setHeader('Cache-Control', 'public, max-age=xxx')
    
    1

    index.html需要协商缓存,则可以这样设置:

    res.setHeader('Cache-Control', 'public, max-age=0')
    res.setHeader('Last-Modified', xxx)
    
    1
    2

    其它语言类似 设置对应返回头就可以了。

    #前端工程化
    上次更新: 2023/04/05, 09:41:10
    vue-cli打包配置
    NPM是什么

    ← vue-cli打包配置 NPM是什么→

    最近更新
    01
    JavaScript-test
    07-20
    02
    二维码的原理
    07-20
    03
    利用ChatGPT优化代码
    07-20
    更多文章>
    Theme by Vdoing | Copyright © 2021-2025 XingYun | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式