浅析浏览器另外三大缓存

本文最后更新于:2020年2月20日 下午

前面分析了浏览器缓存类型之一:HTTP Cache ,接下来简单分析一下浏览器另外的三大缓存机制:Memory CacheService Worker Cache 以及 Push Cache

Memory Cache

Memory Cache 是指内存中的缓存,是浏览器尝试命中的优先级最高的缓存,其响应速度也是最快的。

哪些资源会被放进内存缓存呢?这个没有明确的规定,因为内存本身就是有限的,对于内存来讲,很多时候需要考虑内存的即时余量以及资源本身大小。根据日常开发观察的结果,base64 格式的图片几乎都是被放到内存缓存,文件体积较小的 JS 、CSS 文件,也有很大的几率可以写进内存缓存;至于体积比较大的,用一句俗话来讲,就是“庙小容不了大佛”,几乎是不可能给写进内存缓存的。

内存缓存的响应速度虽然很快,但是相应的,它的“寿命”是比较短的,当我们关闭标签页后,内存里的数据也将不复存在。

Service Worker Cache

service worker 运行在 worker 上下文,因此它无法访问 DOM,同时独立于主线程,可以在浏览器幕后帮我们实现消息推送离线缓存等操作,而借助于 service worker 实现的缓存,就是离线缓存

PS:出于安全考量,Service workers 只能由 HTTPS 承载。

service worker 需要先进行 install (安装),之后会一直存在,并且只在 active (激活)和 working (工作)之间切换,直到我们主动终止。

下面看实践的例子,新建 index.htmlindex.js 两个文件

注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>service worker test</title>
</head>
<body>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('./index.js', {scope: './'})
.then((res) => {
console.log(`注册成功`)
})
.catch(err => {
console.log(`注册失败:${err}`)
})
})
}
</script>
</body>
</html>

第一步,先判断浏览器是否支持 serviceWorker

第二步,浏览器若支持,再通过 register 方法注册 index.js 文件,scope 指定 service worker 控制内容的子目录,该参数为可选参数,默认为根目录;

第三步,通过返回的 Promise ,了解注册成功或失败

安装

1
2
3
4
5
6
7
8
9
10
11
// index.js

this.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'index.html'
])
})
)
})

第一步,通过 install 方法,安装 service worker ;

第二步,这里要注意的是,从安装到激活这个过程需要一些时间,service worker 标准提供一个 waitUntil 方法,当 oninstall 或者 onactivate 触发时被调用,接受一个 promise 。在这个 promise 被成功 resolve 以前,功能性事件不会分发到 service worker ;

第三步,我们在 waitUntil 方法里面使用了 cache.open 来创建一个新的缓存 v1,它返回一个 promise,在被 resolved 之后调用 addAll 方法来添加要缓存的资源的路径;如果被 rejected ,service worker 不会做任何操作。

运行

通过 webstorm 打开 index.html,可以为我们开启一个本地服务器,运行后可以看到:

注册成功

注册成功

缓存成功

缓存成功

使用缓存

我们成功添加缓存之后,接下来就是要使用缓存。

Service Worker 会监听所有的网络请求,网络请求的产生触发的是 fetch 事件,我们可以通过监听 fetch 事件来处理我们的操作。

1
2
3
4
5
6
7
// index.js

this.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
)
})

第一步,监听 fetch 事件;

第二步,通过 respondWith 方法劫持请求;

第三步,可以自定义我们的操作,当然最简单粗暴的就是直接返回我们缓存的资源

再刷新浏览器,可以看到,index.html 来自于 service worker cache

使用serviceWorker缓存

Push Cache

push cache (推送缓存)是比较新颖的东西,属于 HTTP2 ,当前面几种缓存没有命中的时候,才会询问推送缓存。

具体的可以查看 Jake Archibald 大神的 HTTP/2 push is tougher than I thought

文章中有部分结论:

  • Push Cache 是缓存的最后一道防线。浏览器只有在前面说到的几种缓存均未命中的情况下才会去询问 Push Cache;
  • Push Cache 是一种存在于会话阶段的缓存,当 session 终止时,缓存也随之释放;
  • 不同的页面只要共享了同一个 HTTP2 连接,那么它们就可以共享同一个 Push Cache;
  • Push Cache 中的缓存只能被使用一次

结语

理解浏览器缓存,仅仅只是我们对页面性能优化的第一步,更多的性能优化,还在后面的实战中等待我们去完成。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!