前端必知之:从url到dom的中间爱恨情仇——系列二:响应阶段

上篇回顾

前端必知之:从url到dom的中间爱恨情仇------系列一:请求阶段

上篇主要讲解了从url到dom的请求建立连接阶段,当浏览器与服务端建立连接后,开始接收数据,那么接收到的数据从哪里来,又是什么?

响应回来的数据类型

接口返回的数据类型常见的大概就是JSON了,但是还有很多其它的一些数据类型:

1、JSON(JavaScript Object Notation):

  • JSON 是一种轻量级的数据交换格式,易于阅读和编写,也易于机器解析和生成。它基于 JavaScript 语法,但与编程语言无关,因此几乎所有的编程语言都支持 JSON 格式的数据交换。
  • 举一个常见的JSON对象,表示包含一个学生信息的数组,在这个JSON示例中,有两个学生的信息,每个学生都有id、name、age、grades、coursed属性,其中:
    • 'id':表示学生的唯一标识符
    • 'name':表示学生的姓名
    • 'age':表示学生的年龄
    • 'grades':是一个包含学生在不同科目的成绩的对象
    • 'courses':是一个包含学生正在学习的课程的数组
js 复制代码
[
  {
    "id": 1,
    "name": "Alice",
    "age": 20,
    "grades": {
      "math": 85,
      "science": 90,
      "history": 75
    },
    "courses": ["Mathematics", "Physics"]
  },
  {
    "id": 2,
    "name": "Bob",
    "age": 22,
    "grades": {
      "math": 75,
      "science": 80,
      "history": 85
    },
    "courses": ["Chemistry", "Biology"]
  }
]

2、XML(eXtensible Markup Language):

  • XML 是一种可扩展的标记语言,用于描述数据。与 JSON 类似,XML 也是一种通用的数据格式,可用于跨平台和跨语言的数据交换。
  • 下面举一个简单示例,与上述的JSON数据表示的一致:
    • 每个学生都被''元素包围,而学生的属性则以标签的形式表示,如 <id><name><age>
    • <grades><courses> 元素表示学生的成绩和课程列表,而其中的子元素则表示具体的科目或课程。
    • XML 与 JSON 相比,更具有层次感和结构性,但也因此更加冗长。
xml 复制代码
<students>
  <student>
    <id>1</id>
    <name>Alice</name>
    <age>20</age>
    <grades>
      <math>85</math>
      <science>90</science>
      <history>75</history>
    </grades>
    <courses>
      <course>Mathematics</course>
      <course>Physics</course>
    </courses>
  </student>
  <student>
    <id>2</id>
    <name>Bob</name>
    <age>22</age>
    <grades>
      <math>75</math>
      <science>80</science>
      <history>85</history>
    </grades>
    <courses>
      <course>Chemistry</course>
      <course>Biology</course>
    </courses>
  </student>
</students>

3、CSV(Comma-Separated Values):

  • CSV 是一种简单的文本格式,用于将表格数据存储为纯文本。数据以逗号分隔,并且通常每行代表一个数据记录。
  • 以下是一个简单的 CSV 示例,表示同样的学生信息:
    • 在这个 CSV 示例中,每一行代表一个学生的信息,而每个字段则用逗号分隔。第一行是标题行,描述了每个字段的含义。
    • 与 JSON 和 XML 相比,CSV 格式更加紧凑,但缺乏结构性,因为它仅仅是一种简单的纯文本格式,无法直接表示复杂的嵌套结构
csv 复制代码
id,name,age,math,science,history,courses
1,Alice,20,85,90,75,"Mathematics,Physics"
2,Bob,22,75,80,85,"Chemistry,Biology"

4、YAML(YAML Ain't Markup Language):

  • YAML 是一种人类可读的数据序列化格式,通常用于配置文件和数据交换。它的语法简洁,易于理解和编写。
  • 以下是一个简单的 YAML 示例,表示同样的学生信息
    • 在这个 YAML 示例中,学生信息被表示为一个包含两个学生的列表。
    • 每个学生信息被缩进表示其属于相同的列表项。
    • 每个学生都有 id、name、age、grades 和 courses 属性,其中 grades 和 courses 是嵌套的对象和列表。
    • 与 JSON 类似,YAML 也使用缩进来表示层次结构,但 YAML 通常比 JSON 更易读和编写
yaml 复制代码
students:
  - id: 1
    name: Alice
    age: 20
    grades:
      math: 85
      science: 90
      history: 75
    courses:
      - Mathematics
      - Physics
  - id: 2
    name: Bob
    age: 22
    grades:
      math: 75
      science: 80
      history: 85
    courses:
      - Chemistry
      - Biology

5、Protocol Buffers:

  • Protocol Buffers 是一种高效的二进制数据序列化格式,由 Google 开发。它通常用于高性能的网络通信和数据存储,可以生成各种编程语言的代码库

  • Protocol Buffers 是一种二进制序列化格式,它通常与 Protocol Buffers 编程接口一起使用,而不是直接编辑

  • 因此,我提供一个示例 Protocol Buffers 的定义文件(.proto 文件),以及使用该文件生成的一个示例消息

    • 假设我们有一个简单的消息类型,表示学生信息,以下是对应的 .proto 文件:
protobuf 复制代码
syntax = "proto3";

message Student {
  int32 id = 1;
  string name = 2;
  int32 age = 3;
  map<string, int32> grades = 4;
  repeated string courses = 5;
}
go 复制代码
然后,我们可以使用 Protocol Buffers 的编译器将这个 .proto 文件编译
成对应的编程语言的类,例如使用 `protoc` 编译器编译成 `Python` 代码:
bash 复制代码
protoc --python_out=. student.proto
go 复制代码
这将生成一个 Python 文件(假设文件名为 `student_pb2.py`),
我们可以在代码中使用这个文件中定义的类来创建和操作 Protocol Buffers 消息。

以下是一个使用 Python 代码创建和序列化一个学生信息的示例:
python 复制代码
import student_pb2

# 创建一个 Student 对象
student = student_pb2.Student()
student.id = 1
student.name = "Alice"
student.age = 20
student.grades["math"] = 85
student.grades["science"] = 90
student.grades["history"] = 75
student.courses.extend(["Mathematics", "Physics"])

# 序列化为二进制格式
serialized_data = student.SerializeToString()
print("Serialized data:", serialized_data)
scss 复制代码
在这个示例中,我们首先创建了一个 Student 对象,并设置了其属性。
然后,我们使用 `SerializeToString()` 方法将这个对象序列化为 Protocol Buffers 的二进制格式。
最后,我们打印出序列化后的二进制数据。

6、MessagePack:

  • MessagePack 是一种轻量级的二进制数据序列化格式,类似于 JSON,但比 JSON 更快速、更紧凑。它通常用于高性能的数据交换和存储。
  • 以下是一个示例 MessagePack 数据,表示同样的学生信息
    • 类似于 JSON,但比 JSON 更快速、更紧凑
    • 在这个 MessagePack 示例中,学生信息被编码为二进制数据。
    • 尽管这些数据并不可读,但 MessagePack 通过使用更少的字节来表示相同的信息,从而提供了比 JSON 或 XML 更高效的数据交换格式。
msgpack 复制代码
��students���id��name�Alice�age��grades�\�math�U�science�^�history�K�courses��Mathematics�Physics�

缓存

概念

浏览器的缓存就是浏览器保存通过HTTP获取的所有资源,是浏览器将网络资源存储到本地的一种行为。浏览器的缓存机制是根据HTTP报文的缓存标识进行的。

目的

提升用户访问网页的速度,节约网络的资源,浏览器在用户磁盘上对最近的请求过的数据资源进行存储,当访问者再次请求这个页面的时候,浏览器就可以从本地磁盘读取数据资源,这样就可以加速页面的阅览。

缓存流程

缓存概念介绍

浏览器的缓存策略分为两种:强缓存(Expires,cache-control)和协商缓存(Last-modified,Etag),并且缓存策略都是通过设置HTTP Header来实现的。

缓存实际使用方案

当项目改版后,可以获取最新的页面,更新HTML文档;若是版本未变化,则可以继续使用原来的HTML文档资源;

HTML文档配置协商缓存

JSCSS图片配置强缓存

强缓存

访问页面时,如果response Header中有cache-controlexpires字段,代表该资源会进入强缓存的校验判断:

Expires

资源过期时间,值为一个时间戳,当浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存

Cache-Control

  • 取值:
    • max-age: 缓存保质期,是相对时间
    • pubilc: 资源 客户端和服务器都可以缓存
    • privite: 资源 仅客户端可以缓存
    • no-cache: 客户端缓存资源,但是是否缓存需要经过协商缓存来验证
    • no-store: 不使用缓存

Expires与Cache-Control区别

  • Expires是http1.0的产物,Cache-Control是http1.1的产物
  • 两者同时存在,Expires优先级
  • Expires是一个具体的服务器时间戳,但是浏览器的时间和服务器的时间存在一定差异,缓存命中与否不一定准确;Cache-Control是一个时间段

协商缓存

当缓存没有命中强缓存,且Cache-Control的值为no-cache,或者Cache-Control: max-age=0,浏览器会携带缓存标识向服务器发送请求,服务器根据缓存标识来决定该资源是否过期

协商缓存流程

Last-Modified

文件在服务器最后被修改的时间

Etag

服务器生成的当前资源文件的一个唯一标识,若文件内容发生变化,该值就会改变,且Etag优先级比Last-Modified

If-Modified-since

上一次客户端请求该资源时,服务器返回的Last-Modified的值

If-None-Match

上一次客户端请求该资源时,服务器返回的Etag的值

问题汇总

判断哪些资源是从缓存中获取?

在控制台的Network,且记得关闭Disable cache

Sizememory cachedisk cache标识的表示从缓存中来

memory cache和disk cache

两者都属于强缓存,默认情况下,浏览器会将JS图片等文件解析执行后直接存入内存中,这样刷新页面时,只需直接从内存中读取;而CSS文件则会存入到硬盘文件中,所以每次渲染页面都会从硬盘中读取缓存。

特点:

  • memory cache:当前tab页关闭后,资源被释放掉了,再次打开相同的页面,原来的memory cache会变成disk cache;

  • disk cache: 当前tab页关闭后,资源不会释放,再次打开相同的页面,还是disk cache

区别:

  • memory cache表示缓存来自内存,disk cache表示缓存来自硬盘

  • memory cache比disk cache快很多,从磁盘访问可能需要5-20毫秒,而内存访问只需要100纳秒甚至更快;

为什么CSS会放在硬盘缓存中?

因为CSS文件加载一次就可渲染出来,我们不会频繁读取它,所以它不适合缓存到内存中,但是js之类的脚本却随时可能会执行,如果脚本在磁盘当中,我们在执行脚本的时候需要从磁盘取到内存中来,这样IO开销很大了,有可能导致浏览器失去响应。

为啥需要有Etag

主要是为了解决一下Last-Modified中一些难处理的问题:

  • 一些文件也许会是周期性的改变,但是内容并不改变(仅仅改变的修改时间),这时候并不希望客户端认为这个文件被修改了而重新去请求;

  • 某些文件修改非常频繁,比如在1s内修改了多次,if-modified-since能检查到的粒度是秒级的,使用Etag就能保证这种需求在1秒内能多次改变;

缓存存储位置有哪些

浏览器缓存一共有四个位置,当依次查找缓存且都没有命中的时候,才会去请求网络。

  • 四个位置,且优先级从上到下:
    • Service Worker
    • Memory Cache
    • Disk Cache
    • Push Cache

Service Worker

  • Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。

  • 使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。

  • Service Worker 的缓存与浏览器其他内建缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。

  • Service Worker 实现缓存功能一般分为这几个步骤:

    • 首先需要先注册 Service Worker

    • 监听到 install 事件

    • 缓存需要的文件

    • 在下次用户访问的时候通过拦截请求的方式查询是否存在缓存,存在缓存,直接读取缓存文件,否则就去请求数据

  • 当 Service Worker 没有命中缓存的时候,调用 fetch 函数获取数据。也就是说,如果我们没有在 Service Worker 命中缓存的话,会根据缓存查找优先级去查找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据,浏览器都会显示我们是从 Service Worker 中获取的内容。

Memory Cache

  • Memory Cache 也就是内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式脚本图片等。

  • 读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。

  • 一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。

  • 内存缓存在缓存资源时并不关心返回资源的HTTP缓存头Cache-Control是什么值,同时资源的匹配也并非仅仅是对URL做匹配,还可能会对Content-TypeCORS等其他特征做校验。

Disk Cache

  • Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量存储时效性上。

  • 它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。

  • 并且在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。

  • 绝大部分的缓存都来自 Disk Cache。

Push Cache

  • Push Cache(推送缓存)是 HTTP2.0 中的内容,当以上三种缓存都没有命中时,它才会被使用。

  • 它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在Chrome浏览器中只有5分钟左右。

  • 同时它也并非严格执行HTTP头中的缓存指令。

  • 它有如下的一些特性

    • 所有的资源都能被推送,并且能够被缓存,但是 EdgeSafari 浏览器支持相对比较差。
    • Push Cache 中的缓存只能被使用一次
    • 可以给其他域名推送资源
    • 浏览器可以拒绝接受已经存在的资源推送
    • 一旦连接被关闭,Push Cache 就被释放
    • 可以推送 no-cacheno-store 的资源
    • 多个页面可以使用同一个HTTP/2的连接,也就可以使用同一个Push Cache。这主要还是依赖浏览器的实现而定,出于对性能的考虑,有的浏览器会对相同域名但不同的tab标签使用同一个HTTP连接。

下一期预告

  • 三、渲染阶段
    • 1、浏览器内核
    • 2、HTML解析
    • 3、CSS解析
    • 4、渲染树构建
    • 5、节点布局
    • 6、页面渲染

引用:

浏览器缓存机制

一文彻底弄懂浏览器缓存

相关推荐
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
SRY122404193 小时前
javaSE面试题
java·开发语言·面试
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、5 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
不二人生6 小时前
SQL面试题——连续出现次数
hive·sql·面试
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui