Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器缓存 #12

Open
Adamwu1992 opened this issue Feb 2, 2019 · 3 comments
Open

浏览器缓存 #12

Adamwu1992 opened this issue Feb 2, 2019 · 3 comments
Labels
浏览器 关于浏览器相关表现的原理

Comments

@Adamwu1992
Copy link
Owner

Adamwu1992 commented Feb 2, 2019

以下的表述是指在Chromium浏览器下的表现,其他的浏览器可能又不一样的实现。

优先级 持久化 命中规则 作用范围
Memory Cache 1 No URL Navigation
Service Worker 2 Yes 自定义 Host
HTTP Cache 3 Yes HTTP语义 Cros Sessions and Sites
PUSH Cache 4 No HTTP语义 HTTP/2 session

Memory Cache

内存缓存(Memory Cache)是一个巨大的资源容器,渲染引擎(renderer)在渲染当前文档期间抓取的所有的资源都储存在其中,并且在文档生命周期内一直存在。

但是Memory Cache是一个短期缓存,它只会在下一个导航前保存这些缓存,有些情况下可能更短。

有很多用情况你请求的资源已经被缓存在Memory Cache中了:

  • 最有可能被预加载器(Preloader)获取。如果你的请求是由HTML解析器创建DOM时创建的,那么很有可能在Preloader的HTML标记化阶段就已经获取到了。
  • 预加载(<link rel=preload>)指令。
  • 之前的DOM阶段或者CSS规则引起的请求。比如一个页面上,如果有多个img标签引用同一个图片资源,后面的标签请求的资源就会在Memory Cache中。

但是Memory Cache不会轻易的命中一个请求,除了要有匹配的URL,还要有相同的资源类型、CORS模式以及一些其他特性。

Memory Cache匹配规则在标准中没有详尽的描述,所以不同的浏览器内核在实现上会有所不同。

Memory Cache是不关心HTTP语义的,比如Cache-Control: max-age=0的资源,仍然可以在同一个导航中被重用。但是在特定的情况下,Memory Cache会遵守Cache-Control: no-store指令,不缓存相应的资源。

Service Worker

Memory Cache不同的是Service Worker没有任何预设的规则,它完全取决于开发者如何设置它。

Service WorkerMemory Cache主要的区别就是它是持久化的,即使tab页关闭或者浏览器重启,保存在Service Worker缓存里的资源不会消失。

一种删除Service Worker缓存的方法是使用JS代码,cache.delete(resource);还有一种导致缓存被删除的情况是触发了系统的存储空间上限,此时页面的Service Worker缓存连同indexedDB, localStorage等都会一起被回收掉。

Service Worker仅仅在某个限定的作用域内生效,大多数情况下仅对单个host内的文档发起的请求生效。

HTTP Cache

HTTP Cache也被叫做Disk Cache

首先,HTTP Cache是持久化的,并且允许跨session甚至是跨站点地重用。如果一个资源被一个站点缓存在HTTP Cache中,另一个站点如果有相同的请求,是可以重用的。

其次,HTTP Cache是遵循HTTP语义的。它总是会储存最新的资源,验证需要被验证的资源,拒绝储存它不应该储存的资源,这些都是由资源的响应头决定的。

既然它是一个持久化的缓存,就需要某种机制去删除缓存。和Service Worker不同的是它可以逐条删除,当浏览器需要空间去储存更加新鲜或者更加重要的缓存的时候,旧的缓存就会被删除。

HTTP Cache有一个基于缓存的组件,用来匹配请求的资源是否命中它已有的缓存资源,如果有发现命中的资源,它需要从硬盘里取获取这个资源,这是一个昂贵的操作。

我们之前提到HTTP Cache是遵循HTTP语义的,这几乎是完全正常的,只有一个例外的情况:当一个资源是为了下个导航被预抓取回来的(通过<link rel=prefetch> 或者浏览器的其他内部逻辑),即使它是不可储存的,它也将会被保留到下个导航。所以当这些预抓取资源到达HTTP Cache时,它将被保留大约5分钟,并且期间不会被重新验证。

Push Cache

Push Cache是HTTP/2推送的资源存储的地方。它是HTTP/2会话的一部分。如果HTTP/2会话关闭了,储存在其中的资源都会消失。从不同的会话发起的请求将不会命中Push Cache中的资源。所有未被使用的资源在Push Cache会储存优先的时间(Chromium浏览器大约5分钟)。

Push Cache根据请求的URL以及请求表头来匹配资源,但是不是严格遵守HTTP语义的。

如果一个请求命中了Push Cache里的资源,那么这个资源将会从Push Cache里移除,然后经过HTTP Cache时,会保留一份拷贝缓存下来,再经过Service Worker(如果有)时,也会保留一份拷贝储存下来,最后请求的资源回到渲染引擎时,Memory Cache会存储一份对该资源的引用,如果将来本导航会话中的相同的资源请求,这份引用就可以直接被分配给该请求。

参考

@xgqfrms
Copy link

xgqfrms commented May 19, 2020

🕵️‍♂️这块内容,目前看来没有比较正确的答案呀

image

demo

image

image

@Adamwu1992
Copy link
Owner Author

🕵️‍♂️这块内容,目前看来没有比较正确的答案呀

image

demo

image

image

我查阅了关于 preload 的文档,关于缓存的部分还没有被明确定义。

Conceptually, a preloaded response ought to be committed to the HTTP cache, as it is initiated by the client, and also be available in the memory cache and be re-usable at least once within the lifetime of a fetch group.

其中提到的在一个 fetch group 声明周期内,preload 回的资源至少被重用一次才是它最重要的使用场景,至于刷新 tab 后资源从哪里获取,据我观察 preload 目前还是遵循的 http 缓存语义。

@xgqfrms
Copy link

xgqfrms commented May 22, 2020

现在我是这么理解的,

  1. 首先所有的资源第一次加载后,都是存在 memory cache 里面的;浏览器然后,根据 http cache 策略(强缓存/协商缓存),判断某个资源是否要 写入 disk cache;
  2. 后面,刷新页面再次请求资源的时候,浏览器按照(暂不考虑 service worker 等其他缓存)memory cache > disk cache 的顺序依次查找资源,直到命中,或重新请求;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
浏览器 关于浏览器相关表现的原理
Projects
None yet
Development

No branches or pull requests

2 participants