web缓存机制

web缓存机制

​ 在chrome的开发者工具中,在network /Size一列中可以看见一些请求,如果在 这列中明确标明大小KB,B,说明这是一个网络请求,否则一般都会明确标明:from memory cache,from disk cache和from ServiceWorker.

优先级依次是:

  • Service Worker
  • Memory Cache
  • Disk Cache
  • 网络请求

1、Memory Cache

​ 它是内存中的缓存,和硬盘中的缓存相对。几乎所有的网络请求资源都会被浏览器加入到memory cache中去,但由于数量大所以是个短期的存储过程。当浏览的TAB页关闭的时候就失效了。或者一个页面占用的缓存过多的时候会导致前面的TAB缓存还没关闭就失效了。

​ (1)preloader

​ 一般浏览器在打开网站的时候都是请求js/css,之后解析执行,然后再次解析下一个请求这样的穿行操作,那么现在,能不能一边解析js/css,一边请求下一个资源,这就是preloader所干的事。memory cache机制保证了一个页面中若有两个相同的请求的时候,(比如有两个相同href的)都实际上只进行一次请求。在匹配缓存的时候,除了会对他们的URL进行匹配。也会对他们的类型、CORS中的域名规则进行校对。比如在script中缓存的资源不能用在image图片类型的请求中,即使他们的src相同。

​ (2)从memory cache中获取缓存内容的时候,浏览器自动忽略max-age=0,no-cache这些头部配置。因为memory cache只是短时间使用,大部分生命周期只有一次。max-size意思也就是“不要在下次浏览时使用”,和memory cache不冲突。如果真的不想让一个资源进入缓存,即使一次都不想,就可以使用no-store。这样memory cache就不会存储它了

2、disk cache

​ 也叫HTTP cache,是存储在硬盘上的缓存,是持久存储的,实际存在于文件系统当中。允许相同资源跨会话,甚至站点进行使用。他会严格根据HTTP头部信息进行判断哪些资源缓存,哪些可用,哪些过期了需要重新发送请求。命中之后浏览器会从硬盘中去读取资源,虽然过程会比内存中读取慢但是比网络请求快很多。一般大部分的缓存都是来自disk cache。

3.Service Worker

​ 以上的缓存机制和读取,缓存以及失效的行为都是通过浏览器判断进行的,只能通过设置响应的头部告诉浏览器应该做什么。而Service Worker就是一种更直接的方式,这个缓存是永久的,即使关闭TAB或者是关闭浏览器都不能将其删除。只有以下两种情况才会将其删除:手动调用API:cache.delete(resource)或者容量溢出。会被浏览器清除。如果Service Worker没有命中,就会调用fetch()方法继续获取资源。虽然这个时候没有命中Service Worker缓存,用了网络请求,但是在Chrome中依然会被标记为from Service Worker。

4.请求网络

​ 如果前面的三个缓存都没有命中,那么就通过网络请求的方式获取。但是在获取完成之后,需要处理如何将这个资源放在缓存中去的问题:

  • 根据Service Worker中的handle决定是否存入Cache Storage(额外的缓存位置)。
  • 根据HTTP头部的相关字段决定是否存入disk cache
  • memory cache 保存一份资源 的引用

开发与应用

简单的实例

​ 在浏览器端对web的存储,一般都会在Windows上定义两个属性:localStorage和sessionStorage。他们都代表同一个持久化的关联数组,这个数组使用字符串来进行索引,并且在里面存储的所有的数都是以字符串的形式呈现。

​ 接下来我们来通过实例来讲述对于web缓存中在编程上的简单运用。首先我们先来测试一下localStorage这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!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>Document</title>
</head>
<body>
</body>
<script>
var number = 10;
localStorage['number'] = number;
console.log(localStorage['number'])
console.log(typeof(localStorage['number']))
</script>
</html>

​ 这段代码最终的输出是10和string,首先我们定义了一个number,并且在localStorage中的number索引中存放了一个之位10的数。之后将这个值打印出来,可以看见,虽然在我们定义的时候这个number的类型是一个整形的数,但是在存储的时候localStorage将其存储为一个字符串型的数,这对sessionStorage来说也是一样的。并且对于localStorage而言,这个值只要我们不去手动调用相关的函数或是去进行相关的操作删除,他会一直保留在浏览器中。这也就是localStorage和sessionStorage两者的区别。

存储的有效期和作用域

​ 上面说到,localStorage的作用域是永久的,永不过期。他的作用域是限定在文件源级别的。

文档源是通过协议、主机名以及端口三者来确定的。比如下面的例子中每个文档源都是不同的:

​ 在同源文档中共享同样的localStorage数据。可以相互之间进行读写和覆盖对方的数据。但是非同源数据之间就不能够读取或者覆盖。

​ 但是sessionStorage就不一样了。他的有效期是伴随着存储数据的脚本所在的最顶层窗口或是浏览器标签页一 致。如果窗口或者标签页被关闭,那么存储的数据也会被删除。(一些支持回复上次会话的浏览器可能存储的时间会更久点)。同样,sessionStorage的作用域也是限定在文档源中。但是不一样的是,sessionStorage是限定在窗口中的。即使是同源文档但是被渲染到了不同的浏览器标签页(不包括两个iframe元素)的时候,他们互相拥有的是各自的sessionStorage数据,且在这些标签页之间不能共享。互相之间不能进行读写或者覆盖。

存储事件

​ 对于web存储来说还有一个存储事件的监听函数addEventListener()方法,如果一个页面改变了一个值的时候,在另一个标签页中也会收到一个存储时间。对于session而言则是只有两个有牵连的窗口才会触发存储事件。在监听事件的回调函数的参数有几个属性,具体可以查阅相关文档。需要注意的是:localStorage和存储事件是采用的广播机制,浏览器会对访问相同站点的所有窗口发送消息。

相关的介绍

​ cookie是Web浏览器存储的少量数据,也具体的页面或者站点相关。从底层上讲是一种http协议的一种扩展。cookie是可以在Web浏览器和服务器之间传输的,服务器脚本也可以读写客户端的cookie。

cookie的相关属性:

​ cookie具有名和值,还有一些可选的属性设置cookie的有效期和作用域。cookie的作用域只持续在Web浏览器的会话期间,关闭浏览器,cookie就会自动丢失。素以可以通过设置cookie的有效期来延长cookie的有效期。一旦设置,浏览器就会将cookie数据存储在文件中,等到超过了有效期就会删除。同样,cookie的作用域也是通过文档源和文档路径来确定。当然,也可以通过设置cookie的路径(path属性)让其他的页面也能够访问到。比如,对于http://www.baidu.com而言,如果路径是"/cate",那么http://www.baidu.com/cate/index.html等都能够访问,如果直接将路劲设置成"/",那么”http://www.baidu.com/index.html“也可以进行访问。并且,cookie也能实现不同域下的服务器之间读取同一个cookie,只需要设置cookie的domain属性就可以。同时,cookie还有一个属性叫做"secure",表示的是cookie的值以何种形式通过网络传递。默认是通过不安全的形式(HTTP)传递。但如果标记成"安全的",就只能通过HTTPS或者其他的安全协议连接传递。

保存cookie

​ 设置默认的cookie形式就是:name=value。因为cookie中的名或者值是不允许有分毫,逗号或者空白符出现,所以一般存储前需要用JavaScript全局函数encodeURIComponent()进行编码。读取的时候也需要采用decodeURIComponent进行解码。如果想要延长生命周期的话需要用max-age进行指定有效期,设置的单位是秒。之后在读取cookie的时候通过一个例子来说明cookie的存取。

cookie的读取

​ 利用JavaScript读取cookie的时候,返回值一般都是一个字符串,并且是由一串的名和值组成的,不同的对之间使用分号和空格分开,所以需要用split()将其分开。因为前面提到解码问题,所以这时候还需要通过decodeURIComponent进行解码,然后利用JSON.parse()转换成json对象。下面的这个例子说明了函数是如何进行存取cookie的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function setCookie(name,value,time){
var cookie = name + "=" + encodeURIComponent(value);
cookie += "; max-age=" + time;
console.log(cookie)
document.cookie = cookie
console.log(document.cookie)
}
function getCookie(){
var cookie = {};
var all = document.cookie;
console.log(all)
var list = all.split(" ; ")
console.log(list)
}

setCookie('liming',55,120)
getCookie()
0%