浏览器存储技术
作者:Seiya
时间:2019年09月02日
前言
随着移动网络的发展与演化,我们手机上现在除了有原生 App,还能跑“WebApp”——它即开即用,用完即走。一个优秀的 WebApp 甚至可以拥有和原生 App 媲美的功能和体验。WebApp 优异的性能表现,有一部分原因要归功于浏览器存储技术的提升。cookie 存储数据的功能已经很难满足开发所需,逐渐被 WebStorage、IndexedDB 所取代。
Cookie
Cookie 指某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。 cookie是服务端生成,客户端进行维护和存储。
通过cookie,可以让服务器知道请求是来源哪个客户端,就可以进行客户端状态的维护,比如登陆后刷新,请求头就会携带登陆时response header中的 set-cookie,Web 服务器接到请求时也能读出 cookie 的值,根据 cookie 值的内容就可以判断和恢复一些用户的信息状态。
Cookie 的缺陷
Cookie 不够大
Cookie的大小限制在4KB左右,对于复杂的存储需求来说是不够用的。当 Cookie 超过 4KB 时,它将面临被裁切的命运。这样看来,Cookie 只能用来存取少量的信息。此外很多浏览器对一个站点的cookie个数也是有限制的。
过多的 Cookie 会带来巨大的性能浪费
Cookie 是紧跟域名的。同一个域名下的所有请求,都会携带 Cookie。大家试想,如果我们此刻仅仅是请求一张图片或者一个 CSS 文件,我们也要携带一个 Cookie 跑来跑去(关键是 Cookie 里存储的信息并不需要),这是一件多么劳民伤财的事情。Cookie 虽然小,请求却可以有很多,随着请求的叠加,这样的不必要的 Cookie 带来的开销将是无法想象的。
cookie是用来维护用户信息的,而域名(domain)下所有请求都会携带cookie,但对于静态文件的请求,携带cookie信息根本没有用,此时可以通过cdn(存储静态文件的)的域名和主站的域名分开来解决。
由于在 HTTP 请求中的 Cookie 是明文传递的,所以安全性成问题,除非用 HTTPS
LocalStorage
为了弥补 Cookie 的局限性,让“专业的人做专业的事情”,Web Storage 出现了。HTML5 中新增了本地存储的解决方案----Web Storage,它分成两类:sessionStorage和localStorage。这样有了 WebStorage 后,cookie 能只做它应该做的事情了——作为客户端与服务器交互的通道,保持客户端状态。
LocalStorage 的特点
保存的数据长期存在,下一次访问该网站的时候,网页可以直接读取以前保存的数据。
大小为5M左右
仅在客户端使用,不和服务端进行通信
接口封装较好
基于上面的特点,LocalStorage可以作为浏览器本地缓存方案,用来提升网页首屏渲染速度(根据第一请求返回时,将一些不变信息直接存储在本地)。
存入/读取数据
localStorage保存的数据,以“键值对”的形式存在。也就是说,每一项数据都有一个键名和对应的值。所有的数据都是以文本格式保存。存入数据使用setItem方法。
<script>
if(window.localStorage){
localStorage.setItem('name','world')
localStorage.setItem('gender','female')
}
</script>
使用场景
LocalStorage在存储方面没有什么特别的限制,理论上 Cookie 无法胜任的、可以用简单的键值对来存取的数据存储任务,都可以交给 LocalStorage 来做。比如:考虑到 LocalStorage 的特点之一是持久,有时我们更倾向于用它来存储一些内容稳定的资源。比如图片内容丰富的电商网站会用它来存储 Base64 格式的图片字符串:
sessionStorage
sessionStorage 保存的数据用于浏览器的一次会话,当会话结束(通常是该窗口关闭),数据被清空。
sessionStorage 特别的一点在于,即便是相同域名下的两个页面,只要它们不在同一个浏览器窗口中打开,那么它们的 sessionStorage 内容便无法共享;localStorage 在所有同源窗口中都是共享的;cookie 也是在所有同源窗口中都是共享的,除了保存期限的长短不同。
sessionStorage 的特点
会话级别的浏览器存储
大小为5M左右
仅在客户端使用,不和服务端进行通信
接口封装较好
基于上面的特点,sessionStorage 可以有效对表单信息进行维护,比如刷新时,表单信息不丢失。
使用场景
sessionStorage 更适合用来存储生命周期和它同步的会话级别的信息。这些信息只适用于当前会话,当你开启新的会话时,它也需要相应的更新或释放。比如微博的 sessionStorage就主要是存储你本次会话的浏览足迹。
sessionStorage 、localStorage 和 cookie 之间的区别
共同点
:都是保存在浏览器端,且都遵循同源策略。不同点
:在于生命周期与作用域的不同作用域:
localStorage 只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份 localStorage 数据。sessionStorage 比localStorage 更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下;
生命周期:
localStorage 是持久化的本地存储,存储在其中的数据是永远不会过期的,使其消失的唯一办法是手动删除;而 sessionStorage 是临时性的本地存储,它是会话级别的存储,当会话结束(页面被关闭)时,存储内容也随之被释放。
说到底,Web Storage 是对 Cookie 的拓展,它只能用于存储少量的简单数据。当遇到大规模的、结构复杂的数据时,Web Storage 也爱莫能助了。这时候我们就要清楚我们的终极大 boss——IndexedDB!
IndexedDB
IndexedDB 是一种低级API,用于客户端存储大量结构化数据(包括文件和blobs)。该API使用索引来实现对该数据的高性能搜索。IndexedDB 是一个运行在浏览器上的非关系型数据库。既然是数据库了,那就不是 5M、10M 这样小打小闹级别了。理论上来说,IndexedDB 是没有存储上限的(一般来说不会小于 250M)。它不仅可以存储字符串,还可以存储二进制数据。
IndexedDB 的特点
键值对储存
IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
异步
IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
支持事务
IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
同源限制
IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
储存空间大
IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
支持二进制储存
IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
IndexedDB 的常见操作
建立打开IndexedDB ----
window.indexedDB.open("testDB")
这条指令并不会返回一个DB对象的句柄,我们得到的是一个IDBOpenDBRequest对象,而我们希望得到的DB对象在其result属性中
除了 result,IDBOpenDBRequest 接口定义了几个重要属性:onerror
:请求失败的回调函数句柄onsuccess
:请求成功的回调函数句柄onupgradeneeded
:请求数据库版本变化句柄
关闭IndexedDB ----
indexdb.close()
删除IndexedDB ----
window.indexedDB.deleteDatabase(indexdb)
总结
Cookie 的本职工作并非本地存储,而是“维持状态”;
Web Storage 是 HTML5 专门为浏览器存储而提供的数据存储机制,不与服务端发生通信;
IndexedDB 用于客户端存储大量结构化数据;