前端缓存大全

前端缓存是我们前端开发中, 缓存是不可避免的知识点, 最近在复习缓存的知识, 整理了一下浏览器所有缓存类型, 希望供大家参考. 前端的缓存主要分两种, 第一种是网络缓存, 是前端通过网络请求到数据之后, 将数据保存到本地, 当下次再需要请求到相同的数据时, 直接从本地取. 第二种是数据缓存, 是前端通过js将页面执行过程中得到一些数据保存到浏览器中.

网络缓存

网络缓存主要分为在线缓存和离线缓存, 普通缓存又分为强缓存和协商缓存两种, 而离线缓存主要分为Cache Storage和Application Storage两种实现方式.

普通缓存

强缓存

强缓存是通过网络请求到数据时, 就已经确定了缓存的有效时间, 这种缓存一般用于图片等不会轻易发生修改的文件;

cache1.png

例如我们在请求一张图片时, 服务器在返回图片时, 就已经在response header中设置了图片的缓存有效时间, 一般通过Expires 和 Cache-Control 两个字段来设置;

Expires的值是一个固定的日期, 例如图片中的 'Thu, 09 Jan 2020 01:20:33 GMT' 就表示该图片在缓存有效时间到2020年1月9日01:20:33为止, 在这个时间之前请求就用本地缓存的这张图片, 超过这个时间, 则需要向服务器发送请求, 请求新的图片;

Cache-Control的值常见的有两个, 第一个是'no-cache', 表示不使用缓存, 第二个是'max-age=', 表示请求到数据之后, 多少时间内有效, 例如上图max-age=2592000, 就表示请求到图片后的2592000s内有效, 超过这个时间就需要重新发送请求;

如果返回的资源, 同时设有Cache-Control和Expires, 那么以Cache-Control值为准, 因为Expires设置的时间是固定日期, 存在着服务器和浏览器的时区不一致, 导致设置的时间不准确的情况, 所以Cache-Control的优先级大于Expires;

协商缓存

协商缓存是在强制缓存失效后, 浏览器向服务器发起请求, 判断是否继续使用当前的本地缓存的过程;

cache2.png

协商缓存的有效时间同样是由服务器设置, 服务器返回文件时, 就已经在response header中设置了协商缓存的校验时间, 一般通过etag 和 last-modified 两个字段来设置;

last-modified 的值是一个固定的日期, 表示该文件最后修改的时间, 例如上图中设置了'last-modified: Sat, 13 Dec 2019 14:19:52 GMT', 当下次访问服务器时, 就会在请求头中携带'if-modified-since: Sat, 13 Dec 2019 14:19:52 GMT', 询问服务器该时间之后是否修改了文件, 服务器通过对比该资源在服务器中的last-modified时间和携带过来的if-modified-since时间, 如果发生修改, 则直接返回新的资源, 同时携带新的last-modified, 此时状态码为200, 如果没有发生修改, 则直接返回304, 继续使用本地缓存的文件;

而另一个字段etag, 是服务器通过文件内容直接生成的hash值, 所以文件内容发生改变时, etag值也会发生改变, 例如上图的文件hash值为'ALgFrfzd_4_z0yjU_6yZZDqFo-_a', 那么向服务器发送请求时就会在请求头携带 'if-none-math: ALgFrfzd_4_z0yjU_6yZZDqFo-_a', 服务器取到该hash值和服务器中的文件的hash值, 进行比对, 如果两个值一样, 则表示两个文件资源的内容一样, 则没有发生改变, 则返回304, 继续使用本地缓存的文件, 如果两个hash值不一样, 则表示文件内容已经发生了改变, 那么则重新返回新的文件, 此时的状态码为200.

如果文件资源同时又etag和last-modified两个字段, 那么etag的优先级高于last-modified; 因为last-modified只能精确到秒, 如果某些文件在1s内发生多次修改, 那么last-modified就不准确了, 同时也可能存在文件内容没有发生改变, 但是last-modified却发生改变的情况, 所以etag的准确度高于last-modified.

总结

强缓存优先于协商缓存, 强缓存中的Cache-Control优先于Expires, 协商缓存中的etag优先于last-modified.

离线缓存

离线缓存指将页面资源缓存到本地, 使页面在离线环境下也可以进行访问. 离线缓存目前有两种实现方式, 一种manifest实现的离线缓存, 另一种是通过Service Worker实现的离线缓存

manifest

manifest方式实现的离线缓存, 就是通过在html的头部中引入一个.appcache为后缀的文件, 然后用.appcache文件中CACHE属性, 标识出需要缓存的文件, 那些文件就可以实现离线缓存 例如
<html manifest="a.appcache">...</html>,appcache后缀的文件必须和html文件在同级目录下

.appcache文件的主要内容如下:

1、第一行是CACHE MANIFEST 这是必须需要的。

2、CACHE(必须) 标识出哪些文件需要缓存,相对路径/绝对路径。当第一次加载时,会被浏览器缓存在本地。

3、Network 这一部分是要绕过缓存直接读取的文件,可以使用通配符 ,大多数网站使用 * 。 当使用 时 表示出 CACHE指定文件外,其它所有页面都需要联网访问。

4、FALLBACK (可选) 当资源无法访问时,浏览器使用后备资源去替代。第二个表示后备页面。两个 URI 都必须使用相对路径并且与清单文件同源。可以使用通配符。

例如:

cache4.png

通过.appcache文件缓存下来的文件, 可以在谷歌的控制台中的application选项下的, cache中的application cache中查看, 下次访问这些资源时, 就不需要通过网络, 直接从application cache中取, 从而实现离线缓存

cache5.png

Service Worker

Service Worker是浏览器浏览器的一个进程, 可以将其理解为介于客户端和服务器之间的一个代理服务器, 在Service Worker中, 我们可以做很多事情, 比如拦截客户端的请求, 向客户端发送消息, 向服务器发送消息等等. 通过在Service Worker拦截客户端的请求, 用已缓存的资源返回给客户端, 从而实现离线缓存. 另外有一点需要注意的是,出于对安全问题的考虑,Service Worker 只能被使用在 https 或者本地的 localhost 环境下。顺便一提, PWA就是根据Service Worker实现离线缓存的.
Service Worker的注册方式如下, 在页面中运行以下js代码, 注册sw.js文件, sw.js即为Service Worker进程执行的代码

   if ('serviceWorker' in window.navigator) {
     navigator.serviceWorker.register('./sw.js', { scope: './' })
       .then(function (reg) {
         console.log('success', reg);
         navigator.serviceWorker.controller && navigator.serviceWorker.controller.postMessage("this message is from page");
       });
   }

sw.js文件中, 我们就可以用this直接指代Service Worker对象, 然后我们通过给Service Worker监听fetch事件, 每当用户向服务器发送请求时, 这个事件就会被触发,
然后我们使用用户的请求对 Cache Stroage 进行匹配,如果匹配成功,则返回存储在缓存中的资源;如果匹配失败,则向服务器请求资源返回给用户,并使用 cache.put 方法把这些新的资源存储在缓存中Cache

通过Service Worker 缓存静态资源

this.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open('sw_demo').then(function (cache) {
      return cache.addAll([
        '/style.css',
        '/panda.jpg',
        './main.js'
      ])
    }
  ));
}

当 Service Worker 在被安装的时候,我们能够对制定路径的资源进行缓存。CacheStroage 在浏览器中的接口名是 caches ,我们使用 caches.open 方法新建或打开一个已存在的缓存;cache.addAll 方法的作用是请求指定链接的资源并把它们存储到之前打开的缓存中。

但是上诉方法只能缓存固定的资源, 例如'/style.css','/panda.jpg','./main.js', 以下通过拦截所有请求, 将所有的用户的请求对 Cache Stroage 进行匹配,如果匹配成功,则返回存储在缓存中的资源;如果匹配失败,则向服务器请求资源返回给用户,并使用 cache.put 方法把这些新的资源存储在缓存中

this.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.match(event.request).then(res => {
      return res ||
        fetch(event.request)
          .then(responese => {
            const responeseClone = responese.clone();
            caches.open('sw_demo').then(cache => {
              cache.put(event.request, responeseClone);
            })
            return responese;
          })
          .catch(err => {
            console.log(err);
          });
    })
  )
});

缓存在Cache Stroage中的资源可以通过谷歌的控制台中的application选项下的, cache中的Cache中 Storage查看, 下次访问这些资源时, 就不需要通过网络, 直接从Cache中 Storage中取, 从而实现离线缓存


cache6.png

数据缓存

Cookie

Cookie一般用于用户信息的存储, 大小一般不超过4KB, 一般由服务器设置. 服务器为了识别请求者的身份, 在返回的请求头设置, 例如'set-cookie: locale=zh-CN; path=/'


cache3.png

Cookie的主要值如下:

Name: cookie的值对应的别名, 取值时需要用到

Value: cookie的值

Domain: 域名, 即服务器所在的域名, 当访问的域名和该值一样时, 此cookie就会被一起携带到服务器

Path: 路径, 当域名匹配时, 再判断path是否与请求的url的路径是否一样, 通过设置path的值, 可以过滤同个域名下, 不需要携带到服务器的cookie值, 减少请求头的体积

Expires/max-age: cookie的有效时间

Size: cookie大大小

HttpOnly: 是否仅由服务器设置, 如果该值设置为true, 那么前端就无法通过js代码访问该cookie的值, 保证该cookie无法被修改, 从保证cookie的安全性

Secure: 安全性, 该值设置为true时, 则只有https协议时才会把cookie携带到服务器

SameSite: 跨站点限制, 可选值为'strict/lax/none', 通过设置跨站点的不发送cookie, 可以有效防止CSRF攻击

SessionStorage && LocalStorage

SessionStorage和LocalStorage是网页在运行时, 通过js保存到本地的数据, 大小一般不超过5m, SessionStorage与LocalStorage的区别在于SessionStorage在页面关闭时数据会消失, 而LocalStorage则会一直保存在本地.

WebSql && IndexedDB

cache7.png

上诉两种缓存我们都介绍了他们存储容量, cookie一般4KB左右, sessionstorage和localstorage一般5M, 如果前端需要存储到数据量比较大数据时, 就需要用到WebSql和IndexedDB; WebSql && IndexedDB 相当于后端的数据库, WebSql是关系型数据库, 类似于mysql, IndexedDB是非关系型数据库, 类似于mongodb; WebSql && IndexedDB的存储容量和硬盘大小直接挂钩, 可以满足我们存储大容量的数据, 例如用网易云信的sdk, 搭建的聊天室, 就是把聊天记录保存在IndexedDB中. 但是WebSql && IndexedDB目前只有在pc端的谷歌浏览器兼容性比较好, 上诉两种数据库的api大家可以去官网补充了解.

总结

上诉只是对各种缓存, 做了一个比较全的整理, 但并没有对各个缓存方式做太深入讲解, 大家可以通过以此作为线索, 对每个知识点做更加深入的研究, 希望对大家有帮助.

参考文献:

WebSql: https://www.runoob.com/html/html5-web-sql.html

IndexDB: http://www.ruanyifeng.com/blog/2018/07/indexeddb.html

Service Worker: https://blog.csdn.net/huangpb123/article/details/89498418

manifest: https://blog.csdn.net/wang_gongzi/article/details/82846309

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容