前端需要了解的浏览器缓存知识

前言

作为一个前端开发者,每天都在和浏览器打交道,对于浏览器缓存,相信都不会陌生,同时它也是我们日常开发中存在的一个非常重要的优化手段,无论在节省带宽、提高加载和渲染速度、减少网络阻塞,以及提高用户体验上,都有重要的作用。

为什么需要浏览器缓存?

对于浏览器缓存,主要针对的是前端的静态资源,最好的效果是,在发起请求后,拉取相应的静态资源,并保存在本地。如果服务器的静态资源没有更新,那么在下次请求的时候,直接从本地读取资源即可;如果服务器的静态资源已经更新,那么我们再次请求的时候,就要去服务器拉取新的资源,并保存到本地。这样就大大减少了请求次数,提高网站性能。这就用到浏览器的缓存策略了。

总之使用浏览器缓存,有以下优点:

  • 加快客户端网页加载速度,减少用户等待时间,提升用户体验,直接从内存或磁盘中取缓存数据肯定是比从服务器请求更快的。
  • 减少了冗余的数据传输。
  • 减少服务器的负担,大大提升了网站性能。

DNS缓存

这是我们输入网址后,最开始的一个缓存;通常我们输入一个网址,它包含了域名端口可以指定唯一的IP地址,然后建立连接进行通信,而域名查找IP地址的过程就是DNS解析

www.baidu.com (域名) - DNS解析 -> 180.76.76.76 (IP地址)

这个过程会对网络请求带来一定的损耗,所以浏览器在第一次获取到IP地址后,会将其缓存起来。下次相同域名再次发起请求时,浏览器会先查找本地缓存,如果缓存有效,则会直接返回该IP地址,否则会继续开始寻址之旅。
关于寻址过程请看我之前的文章 浏览器从输入URL到页面渲染加载的过程(浏览器知识体系整理)

访问缓存优先级

在这里插入图片描述
备注:
memory cache =》浏览器内存缓存
disk cache =》 硬盘缓存

  1. 先在浏览器内存中查找,如果有,直接加载。
  2. 如果内存中不存在,则在硬盘中查找,如果有直接加载。
  3. 如果硬盘中也没有,向服务器发起网络请求。
  4. 请求获取的资源缓存到硬盘和内存。

下面将从 缓存位置缓存策略 两个角度介绍浏览器缓存。

缓存位置

浏览器中的缓存位置,按优先级从高到低排列分别是:

  • Service Worker
  • Memory Cache
  • Disk Cache

Service Worker

Service Worker 借鉴了 Web Worker的 思路,即让 JS 运行在主线程之外,是一个独立的线程,它的特点是:

  • 主要功能就是拦截请求缓存资源

  • 独立于主线程之外,是一个独立的线程,不会造成阻塞;

  • 由于它脱离了浏览器的窗体,因此无法直接访问DOM对象。

  • 提供了很多新的能力,比如离线缓存消息推送网络代理等功能。其中的离线缓存就是 Service Worker Cache

  • 处于安全考虑, Service Worker 采用 HTTPS 协议;

Service Worker 同时也是 PWA 的重要实现机制,关于PWA ,可以自行百度。

memory cache(浏览器内存缓存)

  • 将资源缓存到内存中,等待下次访问时不需要重新下载资源,而直接从内存中获取。
  • 相比于 disk cache 它的特点是读取速度快,但容量小,且时效性短;不受开发者控制,也不受HTTP协议头的约束。一旦浏览器 tab 页关闭,memory cache 就将被清空,再次重新打开相同页面时不再出现from memory cache的情况。
  • memory cache 会自动缓存所有资源嘛?答案肯定是否定的,当 HTTP 头设置了 Cache-Control: no-store 的时候或者浏览器开发者工具 network 设置了 Disabled cache 禁用缓存后,就无法把资源存入内存了,其实也无法存入硬盘。当从 memory cache 中查找缓存的时候,不仅仅会去匹配资源的 URL,还会看其 Content-type 是否相同。

disk cache(磁盘缓存)

  • 将资源缓存到磁盘中,等待下次访问时不需要重新下载资源,而直接从磁盘中获取。(磁盘==硬盘,可以互换使用的术语)
  • 从存储效率上讲是比内存缓存慢的,但是优势是存储容量大存储时间长等优点。
  • 根据 HTTP 响应头的各类字段进行判定资源的缓存规则,比如是否可以缓存,什么时候过期,过期之后是否需要重新发起请求呢?

memory cache 和 disk cache 对比

-memory cache(内存缓存)disk cache(磁盘缓存)
相同点都是浏览器的本地缓存机制都是浏览器的本地缓存机制
不相同点退出进程时会被清除退出进程时不会被清除
存储资源例如图像、样式表、脚本等保存在内存中一般保存非脚本,如css等

注意

  • 因为CSS文件加载一次就可渲染出来,我们不会频繁读取它,所以它不适合缓存到内存中,但是js之类的脚本却随时可能会执行,如果脚本在磁盘当中,我们在执行脚本的时候需要从磁盘取到内存中来,这样IO开销就很大了,有可能导致浏览器失去响应。
  • 无论是内存缓存还是硬盘缓存,都存在强缓存和协商缓存的概念。具体使用哪种缓存策略取决于服务器返回的响应头信息和浏览器的缓存配置。

缓存策略 - 强缓存和协商缓存

在这里插入图片描述

根据 HTTP header 的字段将缓存分为两个部分,分别是强缓存协商缓存

  1. 强缓存:使用强缓存策略时,如果缓存资源在过期时间内,是的话直接从本地缓存中读取资源,不与服务器进行通信。
  2. 协商缓存:如果强缓存失效后,客户端将向服务器发出请求,进行协商缓存。浏览器携带上一次请求返回的响应头中的 缓存标识 向服务器发起请求(如ETag、Last-Modified等),由服务器判断资源是否更新。如果资源没有更新,则返回状态码 304 Not Modified,告诉浏览器可以使用本地缓存;否则返回新的资源内容。强缓存优先级高于协商缓存,但是协商缓存可以更加灵活地控制缓存的有效性。

强缓存的字段有:ExpiresCache-Control。协商缓存的字段有:Last-ModifiedETag

  • ExpiresCache-Control 都被设置的时候,浏览器会优先考虑后者。
  • Last-ModifiedETag 都被设置的时候,浏览器会优先考虑后者。

1)强缓存

当客户端发出一个请求到服务器,服务器希望你把资源缓存起来,于是在响应头中加入了这些内容:

Cache-Control: max-age=3600  // 我希望你把这个资源缓存起来,缓存时间是3600秒(1小时)
Expires: Mon Oct 17 2023 16:10:32 GMT  // 到达指定时间过期
Date: Mon Oct 16 2023 13:30:30 GMT 
Etag:W/"121-171ca289ebf",// (后面协商缓存内容)这个资源的编号是W/"121-171ca289ebf"
Last-Modified: Mon Oct 16 2023 09:20:10 GMT ,// (后面协商缓存内容)这个资源的上一次修改时间

Cache-ControlExpires分别是HTTP/1.1 和 HTTP/1.0的内容,为了兼容 HTTP/1.0 和 HTTP/1.1,实际项目中两个字段我们都会设置。

浏览器收到这个响应之后就会做下面的事情

  • 浏览器把这次请求得到的响应体缓存到本地文件中
  • 浏览器标记这次请求的请求方法和请求路径
  • 浏览器标记这次缓存的时间是3600秒
  • 浏览器记录服务器的响应时间是格林威治时间2023-10-16 09:20:10

这一次的记录非常重要,它为以后浏览器要不要去请求服务器提供了依据。

判断缓存是否有效就是通过把 max-age + Date,得到一个过期时间,看看这个过期时间是否大于当前时间,如果是,则表示缓存还没有过期,仍然有效,如果不是,则表示缓存失效。

Expires

ExpiresHTTP/1.0的字段,表示缓存过期时间。Expires 需要在服务端配置(具体配置也根据服务器而定),浏览器会根据该过期日期与客户端时间对比,如果过期时间还没到,则会去缓存中读取该资源,如果已经到期了,则浏览器判断为该资源已经过期需要重新从服务端获取。由于 Expires 是一个绝对时间,所以会局限于客户端时间的准确性,从而可能会出现浏览器判断缓存失效的问题。所以出现了Cache-Control,如下是一个 Expires 示例,是一个日期/时间:

Expires: Mon Oct 17 2023 16:10:32 GMT 

到了HTTP/1.0版本,已更改为通过Cache-Controlmax-age来记录了。

Cache-Control

Cache-Controlhttp1.1 时出现的响应头信息,主要通过Cache-Controlmax-age来记录。下面是几个比较常用的设置值:

  • max-age: 最大缓存时间,它是一个相对时间,值的单位是秒,在该时间内,浏览器不需要向浏览器请求。这个设置解决了 Expires 中由于客户端系统时间不准确而导致缓存失效的问题。
  • no-cache: 每次使用前需要向源服务器确认下,防止从缓存中返回过期的资源。
  • no-store: 禁止使用缓存,每次都要重新请求数据,不会被缓存到内存和硬盘。
  • public: 响应可以被任何对象(客户端、代理服务器等)缓存。
  • private:与public相反,缓存服务器会对特定用户提供资源缓存,对于其他用户发送来的请求,代理服务器不会返回缓存。

Cache-Control 的值是可以混合使用的,比如:

Cache-Control: private, max-age=0, no-cache

当强缓存失效的时候,则会进入到协商缓存阶段。

2)协商缓存

一旦发现强缓存无效,浏览器会发送一个请求到服务器,服务器根据请求header中的部分信息来判断资源是否更新。如果没有更新,返回304重定向,告诉浏览器资源未更新,可继续使用本地的缓存;否则返回 状态码200 和 新的资源内容,浏览器缓存新的内容。

这里的请求头header,就是加入了

If-Modified-Since: Mon Oct 16 2023 09:20:10 GMT  你好,你曾经告诉我,这个资源的上一次修改时间是格林威治时间2023-10-16 09:20:10,请问这个资源在这个时间之后有发生变动吗?
If-None-Match: W/"121-171ca289ebf"  你好,你曾经告诉我,这个资源的编号是W/"121-171ca289ebf,请问这个资源的编号发生变动了吗?

其实响应头和请求头的对应关系就是 Last-Modify/If-Modify-SinceETag/If-None-Match

之所以要发两个信息,是为了兼容不同的服务器,因为有些服务器只认If-Modified-Since,有些服务器只认If-None-Match,有些服务器两个都认,但是一般来说 If-None-Match 的优先级高于 If-Modified-Since

Last-Modify / If-Modify-Since

浏览器第一次请求一个资源的时候,服务器返回的 header 中会加上 Last-ModifyLast-Modify是一个时间标识该资源的最后修改时间。
当浏览器再次请求该资源时,请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断资源是否更新。

  • 资源未更新,返回304重定向,表示资源未更新可以继续使用缓存中的资源。
  • 资源更新,返回200状态码,返回新的资源,并进行硬盘和浏览器缓存。

缺点:如果资源更新的速度是小于 1 秒的,那么该字段将失效,因为 Last-Modified 时间是精确到秒的。所以有了 ETag。

ETag / If-None-Match

与 Last-Modify/If-Modify-Since 不同的是,Etag/If-None-Match 返回的是一个校验码。ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化。服务器根据浏览器上发送的 If-None-Match 值来判断是否缓存。
与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。

浏览器的行为

  • 浏览器地址栏输入 URL 后回车: 查找 disk cache 中是否有匹配。如有则使用;如没有则发送网络请求。
  • 普通刷新 (F5 键):因为 tab 页并没有关闭,因此 memory cache 是可用的,会被优先使用(如果匹配的话),其次才是 disk cache
  • 强制刷新 ( Ctrl + F5 键):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache(为了兼容,还带了 Pragma: no-cache)。服务器直接返回 200 和最新内容。
  • 当在开发者工具 Network 面板下设置了 Disabled cache 禁用缓存后,浏览器将不会从 memory cache 或者 disk cache 中读取缓存,而是直接发起网络请求。所以这个按钮注意不要打钩。

不需要缓存的时候

并不是所有请求都能被缓存,无法被浏览器缓存的请求如下:

  • HTTP 信息头中包含 Cache-Control: no-cachepragma: no-cache(HTTP1.0),或 Cache-Control: max-age=0 等告诉浏览器不用缓存的请求;
  • 需要根据 Cookie、认证信息等决定输入内容的动态请求是不能被缓存的;
  • 经过 HTTPS 安全加密的请求;
  • POST 请求无法被缓存;
  • HTTP 响应头中不包含 Last-Modified/Etag,也不包含 Cache-Control/Expires 的请求无法被缓存;

知识拓展

通过前端代码是不能控制缓存的,缓存是后端或者部署的同学来控制的,但是前端同学应该知道那些内容要被缓存,和后端或者部署的同学配合来打!

本文参考
一文读懂浏览器缓存
实践这一次,彻底搞懂浏览器缓存机制
浏览器缓存缓存策略(看完就懂)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
前端性能优化实践# 知识体系与小册格局 ## 写给读者 提起性能优化,大家现在脑海里第一时间会映射出什么内容呢? 可能是类似[“雅虎军规”](https://developer.yahoo.com/performance/rules.html?guccounter=1)和[《高性能 JavaScript》](https://book.douban.com/subject/5362856/)这样历久弥香的经典之作,也可能是搜索引擎聚合给你的一篇又一篇以性能优化为主题的个人或团队实践而来的“私货”。至少当我确定自己的研发方向、并接到第一个性能优化任务时,我做的第一件事是向搜索引擎求助,第二件事是买书,然后开始了摸着石头过河,前后花费了大量的时间和精力。我深感性能优化实在是前端知识树中特别的一环——当你需要学习前端框架时,文档和源码几乎可以告诉你所有问题的答案,当你需要学习 Git 时,你也可以找到放之四海皆准的实践方案。但性能优化却不一样,它好像只能是一个摸索的过程。 这个摸索的过程是痛苦的、漫长的,也是紧要的。因为在如今的互联网环境下,一个前端团队如果只把性能优化这个任务写在纸上,而不投入实践,它将缺失最基本的竞争力。 笔者写这本小册,是希望通过短短十数个章节的讲解,尽可能降低一些大家学习性能优化的成本。 一方面,这本小册为没有接触过性能优化的新同学建立起一个正确的前端性能优化的“世界观”,知道性能优化是什么、为什么、怎么做,从而使性能优化这件事情有迹可循,有路可走。这样在面试现场被问到性能优化层面的问题时,能够做到滔滔不绝、言之有物,而非像背书一样罗列干巴巴的知识点,最终淹没在茫茫的求职大军中。另一方面,小册可以为在职的工程师们提供一线团队已经实践过的“方法论”,知道什么场景下该做什么事情,最终在脑海中留下一张涵盖核心原理和实践的、可随时查阅并且高度可扩展的性能优化思路索引表。然后在今后的开发生活中可以去践行它,更进一步去挖掘它。把性能优化变作你前端工程师生涯的一门必修课,进而演化为自己研发方面的核心竞争力。 同时,相信大家可以明确这样一个学习观念:任何技术的掌握,都离不开一定比例的理论基础和实际操作的支撑。 具体到前端性能优化这件事情上,我认为它是 20% 的理论,加上至少 80% 的实践,甚至很多理论本身也都是我们在具体的业务场景中实践出来的。所以希望大家阅读本小册时,能够读到一些“书本之外的东西”——最好是一边读一边回忆自己既有的开发经历,尝试去留意哪些知识是已知的,哪些是未知的。 这样读完之后,就可以有的放矢地把这些知识转换为自己的项目实践——前端技术日新月异,性能方案永远都在更迭,所以一定要形成自己的学习思路。 建议每一位读者都带着“学了就要用”的心态去读这本小册。如果阅读结束,能够为你带来哪怕一个小小的开发习惯或者优化观念上的改变,这数小时的阅读时间就算没有白费。 ## 知识体系: 从一道面试题说起 在展开性能优化的话题之前,我想先抛出一个老生常谈的面试问题: > 从输入 URL 到页面加载完成,发生了什么? 这个问题非常重要,因为我们后续的内容都将以这个问题的答案为骨架展开。我希望正在阅读这本小册的各位可以在心里琢磨一下这个问题——无须你调动太多计算机的专业知识,只需要你用最快的速度在脑海中架构起这个抽象的过程——我们接下来所有的工作,就是围绕这个过程来做文章。 我们现在站在性能优化的角度,一起简单地复习一遍这个经典的过程:首先我们需要通过 DNS(域名解析系统)将 URL 解析为对应的 IP 地址,然后与这个 IP 地址确定的那台服务器建立起 TCP 网络连接,随后我们向服务端抛出我们的 HTTP 请求,服务端处理完我们的请求之后,把目标数据放在 HTTP 响应里返回给客户端,拿到响应数据的浏览器就可以开始走一个渲染的流程。渲染完毕,页面便呈现给了用户,并时刻等待响应用户的操作(如下图所示)。 ![](https://user-gold-cdn.xitu.io/2018/10/18/16685737b823244c?w=489&h=329&f=png&s=19023) 我们将这个过程切分为如下的过程片段: 1. DNS 解析 2. TCP 连接 3. HTTP 请求抛出 4. 服务端处理请求,HTTP 响应返回 5. 浏览器拿到响应数据,解析响应内容,把解析的结果展示给用户 大家谨记,我们任何一个用户端的产品,都需要把这 5 个过程滴水不漏地考虑到自己的性能优化方案内、反复权衡,从而打磨出用户满意的速度。 ## 从原理到实践:各个击破 我们接下来要做的事情,就是针对这五个过程进行分解,各个提问,各个击破。 具体来说,DNS 解析花时间,能不能尽量减少解析次数
### 回答1: Web前端开发需要掌握的网络基础知识包括: - HTML: 超文本标记语言,用于描述网页的结构 - CSS: 层叠样式表,用于控制网页的外观 - JavaScript: 用于控制网页的行为 - HTTP: 超文本传输协议,用于在浏览器和服务器之间传输数据 - HTTPS: 安全的HTTP协议,用于在浏览器和服务器之间传输加密数据 - AJAX: 异步javascript和XML,用于在网页上实现异步数据交互 - API: 应用程序编程接口,用于网页和服务器之间传输数据 - IP地址,DNS,TCP/UDP,端口号,这些都是基础网络知识 ### 回答2: Web前端开发需要掌握以下网络基础知识: 1. HTTP协议:了解HTTP协议的基本概念、请求方法、状态码、报文格式等。掌握HTTP请求和响应过程,以及常见的HTTP头部字段。 2. 网络通信基础:了解TCP/IP协议族的基本原理和工作机制,包括IP地址、域名解析、端口等。理解TCP和UDP协议的区别和特点。 3. DNS解析:了解域名系统(DNS)的作用和工作原理,包括域名解析过程、DNS缓存等。掌握如何配置和管理域名。 4. 网络安全:了解网络安全的基本概念,包括跨站脚本攻击(XSS)、跨站请求伪造(CSRF)、SQL注入等常见的网络安全问题。学习如何防范和处理这些安全漏洞。 5. WebSocket:了解WebSocket协议的基本原理和特点,能够使用WebSocket实现实时通信功能。 6. 前后端交互:掌握AJAX技术,了解JSON、XML等数据格式的基本概念。能够使用XMLHttpRequest对象向服务器发送异步请求,获取并处理服务器返回的数据。 7. 网络调试工具:掌握常用的网络调试工具,如浏览器开发者工具、Postman等,能够利用这些工具进行网络请求的调试和分析。 8. 前端性能优化:了解前端性能优化的基本原则和常用方法,如压缩资源、合并文件、使用CDN等。能够通过优化网络请求和渲染流程来提升网页的加载速度和响应性能。 总之,掌握了这些网络基础知识,能够更好地理解Web前端开发中的网络交互过程,解决常见的网络问题,并进行性能优化,从而提供更好的用户体验。 ### 回答3: Web前端开发需要掌握以下网络基础知识: 1. HTTP协议:了解HTTP协议的工作原理和常见的请求方法(GET、POST等),了解HTTP头部信息和状态码的含义,以及HTTP的持久连接和缓存等相关概念。 2. HTML和CSS:熟悉HTML和CSS的基本语法和常用标签,了解HTML文档的结构和CSS样式的应用方式,能够根据设计稿实现页面的布局和样式。 3. JavaScript:熟悉JavaScript的基本语法和常用的DOM操作,了解事件处理、Ajax和跨域请求等基本概念,能够编写简单的交互逻辑和动态网页。 4. 网络安全:了解常见的网络攻击方式(如XSS和CSRF)以及相应的防御方法,熟悉HTTPS协议的工作原理和使用方式,能够编写安全性较高的前端代码。 5. 前端性能优化:了解前端页面加载的过程和性能优化的方法,包括减少HTTP请求、压缩和合并静态资源、使用缓存、异步加载等。 6. 浏览器原理:了解浏览器的工作原理,包括渲染引擎的处理流程、页面解析和布局、渲染性能优化等,能够针对不同浏览器进行兼容性处理。 7. 前端框架和工具:熟悉常用的前端框架和工具(如React、Vue、Webpack等),了解它们的工作原理和使用方式,能够快速搭建和优化项目。 综上所述,掌握以上网络基础知识能够使前端开发者更好地理解和应用Web技术,提高开发效率和网页性能,并且能够处理一些网络安全和兼容性问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁锤妹妹@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值