您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    关于Web缓存的那些风流事儿
    时间:2017-04-12 13:33 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    最近大家针对preload、HTTP/2 push和ServiceWorker的浏览器缓存实现展开了激烈的讨论,而这也引起了很多人的疑惑。

    鉴于此,我想讲个故事来让大家了解一个请求如何完成他的使命并找到匹配的缓存资源,以下内容均基于 Chromium 的术语,不过其余浏览器的实现本质上没有太大的差异。

    Questy 的旅程

    Questy 是一个请求。她是在渲染引擎内(也叫渲染器)诞生的。她渴望能在这个标签页关闭前找到一个让她的“人生”再无遗憾的资源。

    关于Web缓存的那些风流事儿

    所以 Questy 展开了她追求幸福的旅程。 但是她会在哪里找到一个恰恰适合的资源呢?

    此时离她最近的是……

    内存缓存(Memory Cache)

    内存缓存中包含了大量的资源。他包含了所有渲染引擎请求的资源。这些资源都是现有文档的一部分。在文档的生命周期中他们都会被储存在此。这意味着,如果 Questy 寻找的资源已经被文档中的其余部分加载了,那么他们会在此相遇。

    确切来说,“短期内存缓存”这个名字可能会更适合。因为内容缓存仅在导航结束前保存这些资源,在某些情况下,时间甚至会更短。

    关于Web缓存的那些风流事儿

    事实上,很多种情况都会导致 Questy 寻找的资源已经被加载。

    预加载器(preloader)可能是最常发生的情况。如果 Questy 是由 HTML 解析器创造的 DOM节点所激发的,那么她很可能会发现,她所寻找的资源早已在 HTML 标记化阶段加载完毕了。

    显示 preload 指令()则是另一种较为可能发生的情况。该指令会让浏览器预加载资源并存储在内存缓存中。

    除此之外,还有可能是因为所请求的资源与之前的 DOM 节点或者 CSS 规则所需要的资源相同。例如,一个页面中可能会含有多个具有相同 src 属性的<img>元素,但是他们会得到同一个资源。而实现这种机制的正是内存缓存。

    然而,内存缓存不会轻易匹配我们的资源请求。当然了,为了使请求和资源相匹配,他们必须要有相同的 URL 。不过,这还不是全部。他们还必须要有相同的资源类型(这样子一个脚本资源才不会被一个图片请求所匹配),相同的 CORS 策略和一些其他特性。

    关于Web缓存的那些风流事儿

    规范并没有十分地明确定义内存缓存所需要匹配的特性,所以不同的浏览器的实现可能会有一定的差异。

    有一样东西是内存缓存不关心的,那就是 HTTP 语义。无论资源的头部是是否带有 max-age=0 或者 no-cache 、Cache-Control标签,内存缓存都不关心。因为在当前导航中,资源是可以重用的,所以 HTTP 语义并不重要。

    关于Web缓存的那些风流事儿

    唯一例外的是no-store指令。在某些特定的情况下浏览器会尊重他。(例如,当资源被单独节点重用时)。

    所以,Questy 走上前询问内存缓存是否有匹配的资源。唉,然而并没有。

    Questy 并没有放弃。她走过资源计时器和开发者工具的网络注册点。在那里,她注册为寻找资源的请求(这意味着如果她能找到匹配的资源,则会出现在开发中工具和资源计时器中)。

    完成了这些官方登记后,她继续向前……

    Service Worker 缓存

    和内存缓存不一样,Service Woker喜欢不走寻常路。他的行为难以预测。因为他只遵循开发者告诉他的规则。

    关于Web缓存的那些风流事儿

    首先,Service Worker只有安装后才会存在。而且因为他的逻辑是由开发者编写的 JavaScript 而不是浏览器控制的,所以 Questy 完全不知道她能不能在这里找到那个他?那个资源长成什么的?他是被存储在缓存里吗?还是说他是由 Service Worker 的主人精心伪造的响应?

    这些问题没有人可以回答她。因为 Service Worker 自成一套,无论是资源的匹配方式还是响应的包装方法,他们都能按照自己的的想法去完成。

    Service Worker 拥有和缓存相关的 API ,这让他可以储存资源。和内存储存不同的是这种存储方式是持久的。即使该标签页被关闭甚至浏览器重启,这些被存储的资源都不会丢失。只有当开发者明确表示要移除他们的时候(使用 cache.delete(resource)),他们才会被移除。另外一种情况就是当浏览器的存储空间不足时,他会将整个 Service Worker 缓存还有其他源存储如 indexedDB、localStorage 等都清除掉。也因此,Service Worker 能确保他的存储和其他源存储是同步的。

    Service Worker 只负责特定的域,换言之,他最多只能管理一个 host。因此,Service Worker 只能控制来自特定域内的文档的请求。

    Questy 走向 Service Worker 询问他有没有合适的资源。可惜的是 Service Worker 从来没有见过那个域的资源,所以他也找不到 Questy 寻找的请求了。于是,Service Worker 让 Questy 继续前行(通过 fetch()),从而在网络栈这片神奇的土地里继续寻找她需要的资源。

    而一旦进入网络栈,最容易找到资源的地方就是……

    HTTP 缓存

    HTTP 缓存(有时候也被他的朋友成为“磁盘缓存”)和 Questy 之前遇到过的缓存不太一样。

    一方面,他们的存储是持久的,而且能被不同的会话甚至不同的网站重用。如果一个资源被一个网站下载了,他也可以被其他网站重用,

    而另一方面,HTTP 缓存遵循 HTTP 语义(名字早已暗示了一切)。他乐于提供他认为觉得是“新鲜”的资源(基于由响应的缓存头声明的生命周期)、校验那些需要重新验证的资源、并拒绝存储那些它不应该存储的资源。

    关于Web缓存的那些风流事儿

    既然他是一个持久性的缓存,他也需要移除资源。但和 Service Worker 不一样的事,他会在觉得他需要空间来存储更重要或者会被更多人需要的资源时,逐个移除那些旧资源。

    HTTP 缓存拥有一个基于内存的组件。他负责为请求匹配资源。可是一旦资源匹配成功,它需要从磁盘中获取资源内容,这是一个较为昂贵的操作。

    (责任编辑:admin)