> 文章列表 > 网络请求实战-缓存、缓存清理和HTTP缓存

网络请求实战-缓存、缓存清理和HTTP缓存

网络请求实战-缓存、缓存清理和HTTP缓存

目录

缓存介绍

清空策略(FIFO)

实战:fifo的memory函数

实战:LRU算法

HTTP缓存

Cache-Control

强制缓存

协商缓存

协商缓存-2(用的最多的)

小结


缓存介绍

早期cpu,内存设计上都有缓存

存储将被用到的数据,让数据访问更快

布隆过滤器(效率更高,牺牲缓存命中率)

  • 命中:在缓存中找到了请求的数据
  • 不命中/穿透:缓存中没有需要的数据
  • 命中率:命中次数/总次数
  • 缓存大小:缓存中一共可以存多少数据
  • 清空策略:如果缓存空间不够数据如何被替换

清空策略(FIFO)

1.先进先出

思考:如果是Javascript缓存,用Map还是Array(Map易读取,Array易清空)

2.LFU-Least Frequently used

优先清除命中次数少的,根据使用频率

内部实现用数组还是优先级队列?(量大的话用数组遍历效率低,可以考虑用优先级队列)

3.LRU-Least recently used

优先清除太久没有使用的,保留最近被使用的缓存,更新最近调用时间

思考:内部实现用数组还是优先级队列?

实战:fifo的memory函数

缓存成立的环境,会做哪些事情

通常是在浏览器上,在端上,整体缓存设置大小限制的

// 先进先出实现方法
function memory(f, maxSize = 10) {// [{hash, value}]const cache = []return (...args) => {const hash = args.join(',')const item = cache.find(x => x.hash === hash)// 循环遍历,找到x.hash === hash 的x   if(item) {return item.value}const result = f(...args)cache.push({hash,value: result})if(cache.length > maxSize) {cache.shift() // 移除第一个值}return result}
}
// 1 1 2 3 5 8 13
// 斐波那契数列(Fibonacci sequence),
// 又称黄金分割数列
function fib(n) {if(n === 1 || n === 2) {return 1}//  递归,前面2个数的和// 因为是递归函数所以,下面mfib用外面那个使用缓存的mfibreturn mfib(n-1) + mfib(n-2) 
}
const mfib = memory(fib, 10)
2^n // 2的n次方
console.log(fib(40))

实战:LRU算法

缓存越来越多的话,会采取的策略

更新最近调用时间

// 优先清除太久没有使用的,保留最近被使用的缓存,更新最近调用时间
function memory(f, maxSize = 10) {// [{hash, value}]let cache = [] // 重新附过值用let//let cache = {}return (...args) => {const hash = args.join(',')const item = cache.find(x => x.hash === hash)if(item) {item.time = new Date().getTime() // 更新调用时间戳return item.value}const result = f(...args)cache.push({hash,value: result,time: new Date().getTime() // 新增时间})if(cache.length > maxSize) {// 删掉时间戳最小的值let min = Infinity // 正无穷let minItem = nullfor(let item of cache) {if(item.time <min) { // 循环比对,把时间戳最小值赋值给min,minItemmin = item.timeminItem = item}}cache = cache.filter(x => x !== minItem) // 保留除了时间戳最小值的数据}return result}
}
// 1 1 2 3 5 8 13
function fib(n) {if(n === 1 || n === 2) {return 1}return mfib(n-1) + mfib(n-2)
}
const mfib = memory(fib, 10)
console.log(fib(40))

 建议用优先级队列,更新一下,上面方法里的on循环

HTTP缓存

Cache-Control

定义所有缓存都要遵守的行为

可缓存性

  • public:允许所有方缓存
  • private:只允许浏览器缓存
  • no-cache:每次必须先询问服务器资源是否已经更新
  • no-store:不使用缓存

缓存期限

  • max-age:秒(存储周期)
  • s-maxage:秒(共享缓存如代理等,存储周期)

强制缓存

强制使用缓存,不去服务器对比;(缓存生效不再发送请求)

Cache-Control: max-age=600(多用这个)

Expires:(用的少)

const express = require('express')
const app = express()
app.get('/x', (req, res) => {// max-age=0 === no-cacheres.set("Cache-Control", 'max-age=600') // 强制缓存,一般用于一定时间内不会变的静态文件res.send("x6")
})
app.listen(3000)
// fetch("/x") // Code: 200 OK (from disk cache)

请求页面,请求接口会用304协商缓存no-cache

协商缓存

协商使用缓存,每次需要向服务器请求对比,缓存生效不传回body

返回: Last-Modified:

请求:If-Modified-Since:

const express = require('express')
const app = express()
app.set('etag', false)// etag也是一种协商缓存,关掉干扰因素
app.get('/x', (req, res) => {res.set("Last-Modified", 'Tue Sep 28 2021 23:41:43 GMT+0800') // 协商缓存,数据更新的最后时间,比较好用res.send("x6")
})
app.listen(3000)

协商缓存-2(用的最多的)

返回:E-Tag:1234567

请求:If-None-Match:1234567

小结

  • 发布新的静态资源的时候,如何更新缓存?

1.每次发布的静态资源文件名都不同(大厂最多策略)

  • HTTP缓存有大小限制吗?FIFO还是LRU

HTTP有大小限制,用端的时候要和端上的同学协商用多大的缓存,

浏览器有自己的限制;CDN也会有限制,只是通常触发不到