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

[浏览器]缓存策略机制详解

在做页面性能优化的时候,有一个点容易被忽略,那就是资源缓存优化。
浏览器里缓存策略分为强缓存协商缓存以及不缓存,每个缓存策略都有其适用的优化场景。
下面为大家详解何为强缓存,协商缓存

先说结论强缓>协商>不缓存。

强缓存

顾名思义,强制缓存,也就是说我的资源请求一次之后,接下来的时间段里如果请求头命中了则直接返回缓存里的资源。通常我们可以在devtools network里看到诸如:
在这里插入图片描述

from (disk or memory) cache这样的描述时,这个资源就是走的强缓存,我们可以查看请求头里的字段
在这里插入图片描述
这里有两个属性要注意,一个是Expires,还有一个是Cache-Control

Expires

expires是http1.0的标准,意思在这个时间段里资源都是有效的,超过这个时间则过期需要重新请求。所以我们在请求时如果命中了expires则不会发起请求而是直接返回缓存(内存或者磁盘,对应的Memory,Disk)里的资源,没有命中则重新发起请求。
它是一个绝对值,所以我们可以修改本地的时间来让资源一直缓存或者直接失效。
正是因为这个不安全的因素,http1.0之后新增了Cache-Control字段来作为命中缓存的依据。

Cache Control

与expires不同 cache-control返回的是一个相对值,相对于资源缓存到服务器的时间。在这个有效期内则不会发起请求而是直接返回缓存,超出同样是发起请求来重新获取资源。


需要注意的是强缓存返回的状态码始终都是200,这点我们可以通过查看network里的大小这一栏来判断是否是强缓存,进而通过请求头来判断当前的缓存策略。
同时,上面我说的结论强缓大于协商的原因是,一旦走了强缓就不会再发起请求,所以自然而然就不会再命中协商缓存了。

协商缓存

同样从名字里我们可以知道,协商协商,肯定是客户端与服务器协商后决定究竟是走缓存呐还是重新发起请求。
协商缓存命中的判断依据是:

  • 首次请求:
    • 会在请求头上带上Last-Modified或者是ETag
  • 第二次请求时:
    • 判断请求头里的if-modified-since是否与Last-Modified相同或者是if-none-match === ETag,一旦有一个条件能达成则直接走缓存,否则就重新发起请求。

协商缓存会先在服务器里判断究竟是要走缓存还是重新发起请求,命中了协商缓存一般请求的状态码是304
在这里插入图片描述
点开请求头我们可以看到if-modified-sinceif-none-match
在这里插入图片描述
通过对比上一次发起的协商请求发现他们是一样的,这样就会命中协商缓存策略。

不缓存

就是不缓存资源,每次请求都拿最新的。
好处是不会被缓存资源困住,坏处是不缓存了每次都请求很耗服务器的性能。



下面通过koa来实现这3个不同的缓存策略机制,新建项目直接npm init -y,然后安装Koa和Koa router

import Koa from 'koa';
import Router from 'koa-router';
import fs from 'node:fs';
import path, { dirname } from 'node:path';
import { fileURLToPath } from 'node:url'const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const app = new Koa();
const filePath = path.join(__dirname, 'example.txt');
const router = new Router();router.get('/strong-cache', async ctx => {const stats = fs.statSync(filePath);const fileContent = fs.readFileSync(filePath, 'utf-8');// 缓存60sctx.set('Cache-Control', 'public, max-age=60');ctx.set('Expires', new Date(Date.now() + 60 * 1000).toUTCString());ctx.type = 'text/plain';ctx.body = fileContent
})router.get('/negotiation-cache', async ctx => {const stats = fs.statSync(filePath);const fileContent = fs.readFileSync(filePath, 'utf-8');const lastModified = stats.mtime.toUTCString();const etag = `"${stats.size}-${Date.parse(stats.mtime)}"`;ctx.set('Cache-Control', 'no-cache');ctx.set('Last-Modified', lastModified);ctx.set('ETag', etag);const ifModifiedSince = ctx.headers['if-modified-since'];const ifNoneMatch = ctx.headers['if-none-match']if ((ifModifiedSince === lastModified) || (ifNoneMatch === etag)) {ctx.status = 304;return;}ctx.type = 'text/plain';ctx.body = fileContent;
})router.get('/no-cache', async ctx => {const fileContent = fs.readFileSync(filePath, 'utf-8');ctx.set('Cache-control', 'no-store');ctx.set('Pragma', 'no-store');ctx.type = 'text/plain';ctx.body = fileContent;
})app.use(router.allowedMethods()).use(router.routes());app.listen(2000, () => {console.log('service run on http://localhost:2000')
})

运行这个服务,打开浏览器 然后在开发者工具devtools里的console里发起fetch请求测试

fetch('/strong-cache').then(res => res.text()).then(res => console.log(res))fetch('/negotiation-cache').then(res => res.text()).then(res => console.log(res))

然后再观察Network请求的情况即可。

http://www.xdnf.cn/news/663931.html

相关文章:

  • (12)Quarkus 编译时增强原理
  • GIS局部放电图绘制指南
  • UE 骨骼模型 会没有face index的原因
  • IPv6能自动分配地址,就不需要DHCP服务器了吗?
  • Unity3D仿星露谷物语开发52之菜单页面
  • RK3568DAYU开发板-平台驱动开发:GPIO驱动
  • 冒险岛 职业名及代码
  • 为什么需要清除浮动?清除浮动的方式有哪些?
  • day28:零基础学嵌入式之进程2
  • MQTT通信协议
  • [面试精选] 0076. 最小覆盖子串
  • Linux多线程(二)之进程vs线程
  • Cell Metab.|复旦大学储以微、骆菲菲团队:Foxp3改造CAR-T,从「能量危机」到「代谢续航」的实体瘤治疗新路径
  • Android GPU Inspector深度解析:从零掌握驱动级性能数据抓取与优化
  • FastAPI 中间件
  • 电子标签倒计时应用
  • 从自发到赋能:产品经理的成长与 AI 时代的自我重塑
  • 测试W5500的第7步_使用ioLibrary库创建HTTP客户端
  • Linux中SHELL脚本常用命令
  • 安卓实用复制功能增强工具
  • 【杂谈】STM32使用快速傅里叶变换库函数后如何比较准确地找到n次谐波幅值
  • Python不要使用可变对象作为函数的默认参数
  • 记忆术-拼音字母形象法【针对“音形义“里谐音法的补充记忆法】
  • 布局泰国遇网络难题?中泰跨境网络组网专线成破局关键
  • Unity中的文件读写TXT 与XML
  • java中的线程安全的集合
  • 如何用DeepSeek修改论文,防止AI幻觉?
  • 题目 3331: 蓝桥杯2025年第十六届省赛真题-LQ 图形
  • 【Axure结合Echarts绘制图表】
  • 华为OD机试_2025 B卷_返回矩阵中非1的元素个数(Python,100分)(附详细解题思路)