系统介绍浏览器缓存机制及前端优化方案

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
.cn 域名,1个 12个月
云解析 DNS,旗舰版 1个月
简介: 系统介绍浏览器缓存机制及前端优化方案

104766ba11d2d7fcb8616085390ee94.png

背景

921ce9ad5b592e1f3a350ebb5ef228d.png

缓存是用来做性能优化的好东西,但是,如果用不好缓存,就会产生一系列问题:

  • 为什么我的页面显示的还是老版本
  • 为什么我的网页白屏
  • 请刷新下网页
  • ...

以上问题大家或多或少都遇到过,归根结底是使用缓存的姿势不对,今天,我们就来一起了解下浏览器是如何进行缓存的,以及我们要怎样科学的使用缓存

浏览器的缓存机制

1. 什么是浏览器缓存?

7b2a797fde8c66fd8211c2e13f2143e.png

简单说,浏览器把 http 请求的资源保存到本地,供下次使用的行为,就是浏览器缓存

这里先记一个点:http 响应头,决定了浏览器会对资源采取什么样的缓存策略

2. 浏览器是读取缓存还是请求数据?

  • 用户第一次请求资源

74bef3c087034316d9256008c1b2858.png

  • 整个完整流程

49636794abac0d9287c000972a31a60.png

3. 缓存过程分类——强缓存 / 协商缓存

根据是否请求服务,我们把缓存过程分为强缓存和协商缓存,也可以理解为必然经过的过程称为强缓存,如果强缓存没有,那在和服务器协商一下

强缓存

强缓存看的是响应头的 Expires 和 Cache-Control 字段

  • Expires 是老规范,它表示的是一个绝对有效时间,在该时间之前则命中缓存,如果超过则缓存失效,并且,由于它是跟本地时间(可以随意修改)做比较,会导致缓存混乱
  • Cache-Control 是新规范,优先级要高于Expires,也是目前主要使用的缓存策略,字段是max-age,表示的是一个相对时间,例如 Cache-Control: max-age=3600,代表着资源的有效期是 3600 秒。

其他配置

no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。

no-store:禁止使用缓存,每一次都要重新请求数据。

public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。

private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。

协商缓存

当强缓存没有命中的时候,浏览器会发送一个请求到服务器,服务器根据 header 中的部分信息来判断是否命中缓存。如果命中,则返回 304 ,告诉浏览器资源未更新,可使用本地的缓存。

协商缓存看的是 header 中的 Last-Modified / If-Modified-Since 和 Etag / If-None-Match

缓存生效,返回304,缓存失效,返回200和请求结果

Etag 优先级 Last-Modified 高

  • Last-Modified / If-Modified-Since

浏览器第一次请求一个资源的时候,服务器返回的 header 中会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存,命中返回304使用本缓存,否则返回200和请求最新资源。

  • Etag / If-None-Match

etag 是更为严谨的校验,一般情况下使用时间检验已经足够,但我们想象一个场景,如果我们在短暂时间内修改了服务端资源,然后又迅速的改回去,理论上这种情况本地缓存还是可以继续使用的,这就是 etag 诞生的场景。

使用 etag 时服务端会对资源进行一次类似 hash 的操作获得一个标识(内容不变标识不变),并返回给客户端。

再次请求时客户端会在 If-None-Match 带上 etag 的值给服务端进行对比验证,如果命中返回304使用缓存,否则重新请求资源。

注:由于 e-atg 服务端计算会有额外开销,所以性能较差

扩展:DNS缓存与CDN缓存

DNS 缓存

我们在网上所有的通信行为都需要IP来进行连接,DNS解析是指通过域名获取相应IP地址的过程。

基本上有DNS的地方就有缓存,查询顺序如下:

019fd439d2c3c8d9164515004ca9a4b.png

一般我们日常会接触到的就是有时内网域名访问需要修改本地host映射关系,或者某些科学上网的情况,可以通过修改本地host来正常访问网址

CDN 缓存

CDN 缓存从减轻根服务的分发压力和缩短物理的传输距离(跨地域访问)上2个层面对资源访问进行优化。

CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低。

大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源服务器的负载。

一般CDN服务都由运营商提供,我们只需要了解如何验证CDN是否生效即可

  • 查看域名是否配置了CDN缓存
    ping {{ 域名 }} 会看到转向了其他地址(alikunlun)
    例如: ping customer.kukahome.com
  • 71e12c3441826b6e05609aeeaea77c1.png
  • 查看我们的页面资源是否命中CDN缓存

通过查看相应头有 X-cache:HIT 字段,则命中CDN缓存,注意这里名称并不固定,但一般都会有HIT标识,如果是MISS 或None之类的,则没有命中缓存

183cd3f40e8f7595aa2657fb56f1698.png

前端针对缓存部署优化方案

构建演进

构建方面优化的核心思想是如何更优,更快速的加载资源,以及如何保证资源的新鲜度

这个优化过程也分为几个阶段,有些其实已经不适用现在的场景,但也可以了解下

  • 早期的图标合并雪碧图(sprite),多脚本文件整理到一个文件:目的是通过减少碎片化的请求数量来加速资源加载(相关知识点是浏览器一般最多只支持6个并发请求,同一时间请求数量需要控制在合理范围)
  • 现在雪碧图已基本被 iconfont 代替,js 加载更多采用分模块异步加载,而不是一味合并
  • 随着 web 应用的推广和浏览器缓存技术的普及,前端缓存问题也随着而来,最常见的就是服务端资源变了,但是客户端资源始终无法更新,这个阶段工程师们想了很多方案。
  • 打包时在静态资源路径上加上 “?v=version” 或者使用时间戳来给资源文件命名
  • 3e6478b719a9c726cb977872ee2414d.png
  • 跟 modified 缓存有点像,由于时间戳并不能识别出文件内容是否变动,所以有了后来的 hash 方案,理论上 hash 出来的文件只要内容不变,文件名就不变,大大提高了缓存的使用寿命,也是现代常用打包工具的默认配置
  • b53cd0206d77e267be07a1757de98dc.png
  • 然后,重点来了,以上我们对 html 文件里链接的资源做了一系列优化,但是 html 本身也是一种静态资源,并且,客户在访问页面时是不会带上所谓的时间戳或者版本号的,导致了很多时候虽然服务端资源更新了,但是客户端还是用老的 html 文本发起请求,这个时候就会导致各种各样的问题了,包括但不限于白屏,展现的旧版本页面等等
  • 26b3255de81d3a7ea3c3df39f8fd5ac.png
  • 为了解决这个问题,目前主流的解决方案是不对 html 进行缓存(一般单页应用html文件较小,大的是 js),只对 js,css 等静态文件进行本地缓存
  • 0b3bb274b948e8176fdb2d6aa64319b.png
  • 那么,如何让浏览器不缓存 html 呢,目前都是通过设置 Cache-Control实现, 有前端方案和后端方案,风险提示,前端方案很不靠谱,后端很多默认配置会覆盖前端方案,可以做了解,生产中请使用后端配置。
    通过 html 标签设置 cache-control
<meta http-equiv="Pragma" content="no-cache" />  // 旧协议
  <meta http-equiv="Expires" content="0" /> // 旧协议
  <meta http-equiv="Cache-Control" content="no-cache" /> // 目前主流
复制代码

部署配置

目前主流的前端部署方式都是使用 nginx,我们来看看 nginx 如何禁用 html 的缓存

location / {
    root **;  
    # 配置页面不缓存html和htm结尾的文件
    if ($request_filename ~* .*.(?:htm|html)$) 
    {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }
    index  index.html index.htm;
}
复制代码
  • Private 会影响到CDN缓存命中率,但本身CDN缓存也会存在版本问题,量不大的情况下也可以禁掉
  • No-cache 可以使用缓存,但是使用前必须到服务端验证,可以是 no-cache,也可以是 max-age=0
  • No-store 完全禁用缓存
  • Must-revalidate 与 no-cache 类似,强制到服务端验证,作用于一些特殊场景,例如发送了校验请求,但发送失败了之类
  • Proxy-revalidate 与上面类似,要求代理缓存服务验证有效性

以上配置可以跟据项目需要灵活配置,考虑到浏览器对缓存协议支持会有些许差异,只是想简单粗暴禁用 html 缓存全上也没有关系,并不会有特别大影响,除非特殊场景需要调优时需要关注。

资源压缩

都讲到这了,前端构建优化还有一个常用的就是 Gzip 资源压缩,可以极大减小资源包体积,前端一般构建工具都有插件支持,需要注意的是也需要 nginx 做配置才能生效

http {
    gzip_static on;
    gzip_proxied any;
}
复制代码

如果生效了,响应头里可以看到 content-encoding: gzip

1ed5d0d6ca42cfb85c2aa24c6a8d364.png


相关实践学习
Serverless极速搭建Hexo博客
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
160 2
|
2月前
|
存储 缓存 监控
|
3月前
|
消息中间件 canal 缓存
项目实战:一步步实现高效缓存与数据库的数据一致性方案
Hello,大家好!我是热爱分享技术的小米。今天探讨在个人项目中如何保证数据一致性,尤其是在缓存与数据库同步时面临的挑战。文中介绍了常见的CacheAside模式,以及结合消息队列和请求串行化的方法,确保数据一致性。通过不同方案的分析,希望能给大家带来启发。如果你对这些技术感兴趣,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
174 6
项目实战:一步步实现高效缓存与数据库的数据一致性方案
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
78 6
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
67 15
Android 系统缓存扫描与清理方法分析
|
1月前
|
前端开发 数据可视化 搜索推荐
深入剖析极态云优雅的前端框架设计方案(上)
最近在体验极态云,这款低代码软件开发产品,发现其前端框架设计方案很优雅很强大! 在接下来的学习过程中,我将持续输出自己对极态云前端框架设计方案的深入理解,包括具体的使用技巧、优势分析以及可能的应用场景等方面的内容,希望能为大家提供有价值的参考。
|
1月前
|
前端开发 JavaScript API
前端开发的秘密花园:这些技巧让你轻松应对各种浏览器兼容性问题!
【10月更文挑战第31天】前端开发是一个充满创意与挑战的领域,追求极致用户体验的同时,浏览器兼容性问题却时常阻碍我们前进。本文将介绍几种解决浏览器兼容性的最佳实践:使用CSS前缀、Autoprefixer工具、现代JavaScript特性与Babel转译、Polyfill与Feature Detection、响应式设计以及跨域问题处理。掌握这些技巧,助你轻松应对各种兼容性难题,创建更稳定、用户友好的网页应用。
30 3
|
1月前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
1月前
|
Web App开发 定位技术 iOS开发
Playwright 是一个强大的工具,用于在各种浏览器上测试应用,并模拟真实设备如手机和平板。通过配置 `playwright.devices`,可以轻松模拟不同设备的用户代理、屏幕尺寸、视口等特性。此外,Playwright 还支持模拟地理位置、区域设置、时区、权限(如通知)和配色方案,使测试更加全面和真实。例如,可以在配置文件中设置全局的区域设置和时区,然后在特定测试中进行覆盖。同时,还可以动态更改地理位置和媒体类型,以适应不同的测试需求。
Playwright 是一个强大的工具,用于在各种浏览器上测试应用,并模拟真实设备如手机和平板。通过配置 `playwright.devices`,可以轻松模拟不同设备的用户代理、屏幕尺寸、视口等特性。此外,Playwright 还支持模拟地理位置、区域设置、时区、权限(如通知)和配色方案,使测试更加全面和真实。例如,可以在配置文件中设置全局的区域设置和时区,然后在特定测试中进行覆盖。同时,还可以动态更改地理位置和媒体类型,以适应不同的测试需求。
50 1
|
1月前
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
65 1