作为一名前端工作人员, 前端的缓存知识是必须掌握的, 因为一个网站打开网页的速度直接关系到用户体验, 用户粘度, 而提高网页的打开速度有很多方面需要优化, 其中比较重要的一点就是利用好缓存, 缓存文件可以重复利用, 还可以减少带宽, 降低网络负荷.
1 缓存
缓存从宏观上分为私有缓存和共享缓存, 共享缓存就是那些能被各级代理缓存的缓存. 私有缓存就是用户专享的, 各级代理不能缓存的缓存.
缓存从微观上可以分为以下几类:
浏览器缓存
代理服务器缓存
CDN 缓存
数据库缓存
应用层缓存
这里主要对浏览器的缓存进行说明:
2 http 缓存
2.1 强缓存
不会向服务器发送请求, 直接从缓存中读取资源
请求返回 200 的状态码
在 Chrome 控制台的 network 选项中可以看到 size 显示 from disk cache 或 from memory cache.
from memory cache 代表使用内存中的缓存, from disk cache 则代表使用的是硬盘中的缓存, 浏览器读取缓存的顺序为 memory -> disk. 在浏览器中, 浏览器会在 JS 和图片等文件解析执行后直接存入内存缓存中, 那么当刷新页面时只需直接从内存缓存中读取(from memory cache); 而 CSS 文件则会存入硬盘文件中, 所以每次渲染页面都需要从硬盘读取缓存(from disk cache).
Expires 和 Cache-Control 两者对比: 其实这两者差别不大, 区别就在于 Expires 是 http1.0 的产物, Cache-Control 是 http1.1 的产物, 两者同时存在的话, Cache-Control 优先级高于 Expires
2.2 协商缓存
协商缓存就是强制缓存失效后, 浏览器携带缓存标识向服务器发起请求, 由服务器根据缓存标识决定是否使用缓存的过程
协商缓存生效, 返回 304 和 Not Modified
2.2.1 Last-Modified 和 If-Modified-Since
浏览器在第一次访问资源时, 服务器返回资源的同时, 在 response header 中添加 Last-Modified 的 header, 值是这个资源在服务器上的最后修改时间, 浏览器接收后缓存文件和 header;
浏览器下一次请求这个资源, 浏览器检测到有 Last-Modified 这个 header, 于是添加 If-Modified-Since 这个 header, 值就是 Last-Modified 中的值; 服务器再次收到这个资源请求, 会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比, 如果没有变化, 返回 304 和空的响应体, 直接从缓存读取, 如果 If-Modified-Since 的时间小于服务器中这个资源的最后修改时间, 说明文件有更新, 于是返回新的资源文件和 200
缺点: 1, 某些服务端不能获取精确的修改时间 2, 文件修改时间改了, 但文件内容却没有变
2.2.2 ETag 和 If-None-Match
Etag 是上一次加载资源时, 服务器返回的 response header, 是对该资源的一种唯一标识, 只要资源有变化, Etag 就会重新生成. 浏览器在下一次加载资源向服务器发送请求时, 会将上一次返回的 Etag 值放到 request header 里的 If-None-Match 里, 服务器只需要比较客户端传来的 If-None-Match 跟自己服务器上该资源的 ETag 是否一致, 就能很好地判断资源相对客户端而言是否被修改过了. 如果服务器发现 ETag 匹配不上, 那么直接以常规 GET 200 回包形式将新的资源 (当然也包括了新的 ETag) 发给客户端; 如果 ETag 是一致的, 则直接返回 304 知会客户端直接使用本地缓存即可.
2.2.3 协商缓存两种方式的对比
首先在精确度上, Etag 要优于 Last-Modified,Last-Modified 的时间单位是秒, 如果某个文件在 1 秒内改变了多次, 那么他们的 Last-Modified 其实并没有体现出来修改, 但是 Etag 每次都会改变确保了精度; 如果是负载均衡的服务器, 各个服务器生成的 Last-Modified 也有可能不一致.
性能上, Etag 要逊于 Last-Modified, 毕竟 Last-Modified 只需要记录时间, 而 Etag 需要服务器通过算法来计算出一个 hash 值.
优先级上, 服务器校验优先考虑 Etag
3 缓存机制
appcache 优先于强缓存, 强制缓存优先于协商缓存进行, 若强制缓存 (Expires 和 Cache-Control) 生效则直接使用缓存, 若不生效则进行协商缓存(Last-Modified / If-Modified-Since 和 Etag / If-None-Match), 协商缓存由服务器决定是否使用缓存, 若协商缓存失效, 那么代表该请求的缓存失效, 返回 200, 重新返回资源和缓存标识, 再存入浏览器缓存中; 生效则返回 304, 继续使用缓存. 具体流程看下图:
不管是浏览器缓存, 还是代理服务器缓存, CDN 缓存都遵循客户端与服务端之间的缓存机制
4, 本地存储
本地存储主要有以下几种, localStorage,sessionStorage 和 cookie,webSql 和 IndexDB 主要用在前端有大容量存储需求的页面上, 例如, 在线编辑浏览器或者网页邮箱. 他们都可以将数据存储在浏览器, 应该根据不同的场景进行使用.
4.1 Cookie
Cookie 主要是由服务器生成, 且前端也可以设置, 保存在客户端本地的一个文件, 通过 response 响应头的 set-Cookie 字段进行设置, 且 Cookie 的内容自动在请求的时候被传递给服务器. 如下:
- [HTTP/1.1 200 OK]
- Server:[bfe/1.0.8.18]
- Etag:["58860415-98b"]
- Cache-Control:[private, no-cache, no-store, proxy-revalidate, no-transform]
- Connection:[Keep-Alive]
- Set-Cookie:[BDORZ=27315; max-age=86400; domain=.baidu.com; path=/]
- Pragma:[no-cache]
- Last-Modified:[Mon, 23 Jan 2017 13:24:37 GMT]
- Content-Length:[2443]
- Date:[Mon, 09 Apr 2018 09:59:06 GMT]
- Content-Type:[text/html]
Cookie 包含的信息:
它可以记录你的用户 ID, 密码, 浏览过的网页, 停留的时间等信息. 当你再次来到该网站时, 网站通过读取 Cookies, 得知你的相关信息, 就可以做出相应的动作, 如在页面显示欢迎你的标语, 或者让你不用输入 ID, 密码就直接登录等等. 一个网站只能读取它自己放置的信息, 不能读取其他网站的 Cookie 文件. 因此, Cookie 文件还保存了 host 属性, 即网站的域名或 ip.
这些属性以名值对的方式进行保存, 为了安全, 它的内容大多进行了加密处理. Cookie 文件的命名格式是: 用户名 @网站地址[数字].txt
Cookie 的优点:
给用户更人性化的使用体验, 如记住 "密码功能", 老用户登录欢迎语
弥补了 HTTP 无连接特性
站点统计访问人数的一个依据
Cookie 的缺点:
它无法解决多人共用一台电脑的问题, 带来了不安全因素
Cookie 文件容易被误删除
一人使用多台电脑
Cookies 欺骗. 修改 host 文件, 可以非法访问目标站点的 Cookie
数量和长度有限制, 最多 20 条, 最长不能超过 40k
在请求头上带着数据安全性差
4.2 localStorage
localStorage 主要是前端开发人员, 在前端设置, 一旦数据保存在本地后, 就可以避免再向服务器请求数据, 因此减少不必要的数据请求, 减少数据在浏览器和服务器间不必要地来回传递.
可以长期存储数据, 没有时间限制, 一天, 一年, 两年甚至更长, 数据都可以使用.
localStorage 中一般浏览器支持的是 5M 大小, 这个在不同的浏览器中 localStorage 会有所不同
优点:
localStorage 拓展了 cookie 的 4k 限制
localStorage 可以将第一次请求的 5M 大小数据直接存储到本地, 相比于 cookie 可以节约带宽
localStorage 的使用也是遵循同源策略的, 所以不同的网站直接是不能共用相同的 localStorage
缺点:
需要手动删除, 否则长期存在
浏览器大小不一, 版本的支持也不一样
localStorage 只支持 string 类型的存储, JSON 对象需要转换
localStorage 本质上是对字符串的读取, 如果存储内容多的话会消耗内存空间, 会导致页面变卡
4.3 sessionStorage
sessionStorage 主要是前端开发人员, 在前端设置, sessionStorage(会话存储), 只有在浏览器被关闭之前使用, 创建另一个页面时同意可以使用, 关闭浏览器之后数据就会消失
存储上限限制: 不同的浏览器存储的上限也不一样, 但大多数浏览器把上限限制在 5MB 以下
4.4 websql
Web SQL 是在浏览器上模拟数据库, 可以使用 JS 来操作 SQL 完成对数据的读写. 它使用 SQL 来操纵客户端数据库的 API, 这些 API 是异步的, 规范中使用的方言是 SQLlite. 数据库还是在服务端, 不建议使用, 已废弃
4.5 indexDB
随着浏览器的功能不断增强, 越来越多的网站开始考虑, 将大量数据储存在客户端, 这样可以减少从服务器获取数据, 直接从本地获取数据.
现有的浏览器数据储存方案, 都不适合储存大量数据: Cookie 的大小不超过 4KB, 且每次请求都会发送回服务器; LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同), 而且不提供搜索功能, 不能建立自定义的索引. 所以, 需要一种新的解决方案, 这就是 IndexedDB 诞生的背景.
通俗地说, IndexedDB 就是浏览器提供的本地数据库, 它可以被网页脚本创建和操作. IndexedDB 允许储存大量数据, 提供查找接口, 还能建立索引. 这些都是 LocalStorage 所不具备的. 就数据库类型而言, IndexedDB 不属于关系型数据库(不支持 SQL 查询语句), 更接近 NoSQL 数据库.
关于 indexDB 的知识可以查看这篇文章
这里, 我只是根据自己的理解整理了一下关于缓存, 存储方面的知识, 还有很多不足的地方, 更多实践的知识, 还请查看其他文章, 如有错误, 请指出
参考文章:
- https://www.jianshu.com/p/54cc04190252
- https://segmentfault.com/a/11...
- http://www.cnblogs.com/etoah/p/5579622.html
来源: https://segmentfault.com/a/1190000017185195