这次我们来讲一下关于前端缓存的问题。感谢赵欢同学提供doc素材。
首先,开局我画了一张图,你会对文章有一个大局了解。
今天讲的是前端缓存。
前端缓存有3大种:如图,分为HTTP缓存、浏览器缓存、应用程序缓存。
我们先来看HTTP缓存:(做下了解)
分为强缓存与协商缓存。
首先看强缓存:
强缓存之Expires:
-
值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据;
-
到期时间是由服务端生成的,客户端时间跟服务端时间可能存在误差,这就会导致缓存命中的误差;
-
被Cache-Control替代;
强缓存之Cache-Control:
参数 |
说明 |
public |
所有内容都将被缓存(客户端和代理服务器都可缓存) |
private |
内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存) |
no-cache |
必须先与服务器确认返回的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载。 |
no-store |
所有内容都不会被缓存到缓存或 Internet 临时文件中 |
must-revalidation/proxy-revalidation |
如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证 |
max-age=xxx |
缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高 |
来举个栗子:
图中Cache-Control仅指定了max-age,所以默认为private,缓存时间为31536000秒(365天)
也就是说,在365天内再次请求这条数据,都会直接获取缓存数据库中的。
协商缓存:(相当于就是浏览器与服务器通过一个值作为更新flag,一个协商一个判断)
协商缓存之Etag/If-None-Match:
-
当浏览器请求服务器的某项资源(A)时,服务器会根据A算出一个哈希值,并通过Etag返回给浏览器,浏览器把ETAG和资源A同时缓存到本地。
-
当下次向服务器请求该资源时,会通过If-None-Match把ETAG发送给服务器。
-
服务器再次计算A的哈希值并和浏览器的返回值作比较,如果A发生了变化就把A返回给浏览器(返回值200),如果未发生变化就返回浏览器304(未修改)
协商缓存之Last-Modified/If-Modified-Since:
-
在浏览器请求服务器的某项资源时,返回资源的同时还有一个Last-Modified的属性标记此文件在服务器端的最后修改时间;
-
浏览器第二次访问该资源时,会向服务器传送 If-Modified-Since报头,询问该时间之后文件是否被修改过;
-
如果服务器的资源没有变化,则时间一致,返回304的状态吗,浏览器使用本地缓存;
-
如果时间不一致,返回200,显示新文件并缓存。
那么Etag和Last-Modified,他们之间有什么区别呢???
-
Etag是标识传输,Last-Modified是时间传输;
-
Etag的优先级高于Last-Modified;
-
Last-modified标注的最后修改时间只能精确到秒,如果文件在1秒以内被多次修改,它不能准确标注文件的最后修改时间;
-
如果文件定期生成,但内容没有任何变化,但是last-modified却改变了,导致没法使用缓存;
-
有可能存在服务器没有准确获取文件修改时间,或与代理服务器时间不一致的情况;
-
etag每次服务端生成都需要进行读写操作,而last-modified只需要读取操作,etag消耗更大些;
各有优劣!
那强缓存与协商缓存,他们的规则分别是什么?
强缓存规则:
-
已失效时,请求服务器,服务器返回数据和缓存规则,客户端将数据和缓存规则存入缓存数据库;
-
未失效时,请求缓存数据库,返回数据并渲染;
协商缓存规则:
-
先到缓存数据库中获取标识Etag/Last-Modified,
-
再通过If-None-Match/If-Modified-Since字段带上缓存标识请求服务器,服务器判断内容是否失效;
这两种缓存的执行流程是怎么样的?
-
强缓存未失效,从缓存中读取数据,cache-control优先级高于Expires;
-
强缓存已失效,执行协商缓存,Etag的优先级高于last-Modified;
-
缓存未失效从缓存中读取数据返回304状态码;
-
缓存已失效返回资源和200状态码;
怎么清除缓存?
浏览器默认会缓存图片,css和js等静态资源,所以开发环境下经常会因为强缓存导致资源没有及时更新而看不到最新的效果,需要清除缓存可以使用一下几种方法:
-
直接ctrl+f5,这个办法能解决页面直接引用的资源更新的问题;
-
使用ctrl+shift+delete清除缓存;
-
如果用的是chrome,可以F12在network那里把缓存给禁掉,选中“disable Cache”:
-
或者给资源文件加一个时间戳;
-
或者禁止修改html中的缓存字段为禁止使用;
-
或者在谷歌浏览器刷新按钮上,点击右键,选择“清空缓存并硬性重新加载”;
然后是浏览器缓存:(这个前端很多时候会用到)
有本地小容量存储与本地大容量存储
小容量的Cookie:
一般用于以下场景:
-
记住用户名密码
-
欢迎语
小容量的LocalStorage:
记录后只要不手动清除就会一直存在。
小容量的SessionStorage:
仅在本次会话时有效。关闭当然窗口后就没有了。
Storage的API如下:(localStorage为例,sessionStorage一样)
保存数据:(3种写法均可)
写法1:
localStorage.setItem("key",value)
写法2:
localStorage["key"]=1
写法3:
localStorage.key=1
读取数据:(相对也有3种)
写法1:
var value=localStorage.getItem("key")
写法2:
var value=localStorage["key"]
写法3:
var value=localStorage.key
删除单个数据:
localStorage.removeItem(key);
删除所有数据:
localStorage.clear();
得到某个索引的key:
localStorage.key(index);
比较一下Cookie、LocalStorage、sessionStorage的异同:
-
cookie会在在同源的http请求中携带,不能超过4K,参与和服务器交互;
-
sessionStorge和locaStorage保存数据在本地,限制最多5M,不参与和服务器交互;
-
sessionStorage仅在当前窗口关闭前有效;
-
localstorage会一直保存在浏览器中,除非手动删除;
-
cookie在设置过期时间之前一直有效,不设置过期时间窗口关闭则清除;
-
sessionStorage不在不同的浏览器窗口*享,即使是同一个页面,
-
localstorage和cookie在所有同源窗口*享
本地大容量存储之WebSql:
表保存数据,用sql操作数据库(写的是sql语句,懂mysql数据库的完全不在话下)
创建表:
create table if not exists product(id integer primary key autoincrement,name text not null,price double);
添加一条数据:
insert into product(name,price) values('斗战圣皇','1.2');
insert into product(name,price) values('布衣神探:最后的证据','0.9');
删除一条数据:
delete from product where id=2;
更新一条数据:
update product set name='斗战圣皇第二部',price='0.99' where id=1;
查询表格:
select * from product;
删除表格:
drop table IF EXISTS product;
本地大容量存储之IndexDB:
保存的是对象类型的数据
-
open()打开或创建数据库
-
deleteDatabase()删除数据库;
-
transaction()打开事物
-
add()添加数据
-
get()查找数据
-
delete()根据ID删除数据
-
clear()清除全部数据
分为应用缓存和PWA
什么是应用缓存?
页面基本结构:
-
html标签上配置manifest文件,文件后缀.appcache;
-
manifest 需要配置 MIME-type,即 "text/cache-manifest"。必须在 web 服务器上进行配置,不同服务器不一样;
如tomcat 需要修改conf/web.xml配置文件,添加:
<mime-mapping>
<extension>manifest</extension>
<mime-type>text/cache-manifest</mime-type>
</mime-mapping>
-
manifest文件的格式个配置,分三部分,缓存文件,不缓存文件,页面无法访问时的回退页面;
CACHE MANIFEST
/theme.html
NETWORK:
login.php
FALLBACK:
/html/ /offline.html
举个栗子:
有网络时:
什么是PWA?
先了解APP和web网页存在的一些不足:
APP应用存在的不足:
-
开发成本高(IOS和安卓)
-
软件上线需要审核
-
版本更新需要上传到应用商店
-
想使用APP必须下载
web网页存在的不足:
-
手机桌面入口不够便捷,需要记住URL或加入书签
-
不能像APP一样推送消息
PWA弥补了APP和web网页存在的一些缺点:
-
是一个web网页应用
-
可以添加至主屏幕,点击主屏幕的图标可以实现启用动画以及隐藏地址栏
-
实现了离线缓存功能,即使手机没有网络,依然可以实现一些离线功能
-
实现了消息推送
一个简单的PWA栗子: