浏览器最原始的本地存储方式是cookies
,后来HTML5提供了新的客户端存储数据的方法:localStorage
和sessionStorage
,以及数据库形式Web SQL
和IndexedDB
。
cookie
作用
cookie
是最原始的本地存储方式,它起到让服务器辨识浏览器身份的作用。
由于HTTP协议是无状态的,即用户在关闭网页的时候,浏览器和服务器的连接就断开了,用户下次登录同一网页时,服务器无法辨识用户的身份。这会带来不好的用户体验。为了解决这一问题,cookie
用来存储用户的身份Id,下一次访问时,浏览器会在请求头中携带cookie
,这样服务器就能够通过cookie
来得知用户身份,同时根据cookie
来找到服务器上存储的用户的相关信息。
cookie
是一段纯文本,数据以键值对的形式保存,每次浏览器发送请求都会携带cookie
。由此可以想象,如果cookie
存储大量的数据,会导致请求非常的缓慢,占用大量网络资源。而如果cookie
只用来存储用户身份信息就比较合适。
事实上,浏览器的确对cookie
的大小作了规定,不同的浏览器允许的cookie
大小不同,但一般都在4kb左右。
特点
- 不同浏览器存放
cookie
的位置不一样,互相不通用 cookie
的存储是以域名的形式区分的,不同域下存储的cookie
是独立的- 设置的
cookie
对当前域和它的子域都有效 - 一个域名下存放的
cookie
个数是有限的,一般为20个
操作
cookie
的值可以读取和设置,也可以删除。
读取
- 浏览器可以直接在控制台中通过
document.cookie
读取当前域的cookie
- 服务端如node.js可以通过
request.cookies
来读取(可能需要中间件解析)
设置
浏览器直接在控制台中通过
document.cookie="xxx=xxx"
的形式来设置1
2document.cookie="name=value";
document.cookie="name=valueldomain=www.baidu.com";浏览器可以设置
cookie
的expires
,domain
,path
,secure
等属性服务器端可以通过
response
的Set-Cookie
方法来设置
修改
修改cookie
只需要按照设置cookie
的方法重新赋值就行了。
删除
把cookie
的过期时间设置成一个过去的时间即可。
HTML Web Storage
HTML web storage, better than cookies.
HTML5之前,页面的数据会存储在cookie中,并在每一次服务器请求中携带发送。HTML5提出了新的本地存储方式,它们更加安全,允许更大量的数据存储到本地,但不会影响到页面性能。
不同于cookies
,新的存储方式提供至少5MB的存储空间,而且存储的信息不会发送给服务器。
网页存储是按源(域和协议)来区分的,所有同源的页面都能够存储和获取相同的数据。
HTML网页存储在浏览器端提供了两个用与存储数据的对象:
window.localStorage
用来存储不会过期的数据window.sessionStorage
用来存储会话数据,即当浏览器标签页关闭时,会话数据会被清空
使用之前,我们可以先检测浏览器是否支持localStorage
和sessionStorage
:
1 | if(typeof Storage !== "undefined"){ |
比如我使用之前做过的一个弹幕项目的页面来测试,可以看见localStorage
里是存储了数据的:
下面是localStorage
的方法。
sessionStorage
里没有数据,但同样有一些方法:
localStorage
localStorage
是HTML5的新方法,不过IE8及以上浏览器都兼容。
localStorage
用来存储没有过期时间的数据,它也是以键/值对的形式存储的字符串。当浏览器关闭时,数据不会被删除,下一次打开浏览器时依然能够使用(除非手动删除数据,否则数据永不过期)。
方法
localStorage.setItem("name", "value");
设置localStorage.getItem("name");
读取1
2
3
4// store
localStorage.setItem("lastname", "Smith");
// Retrieve
document.getElementById("result").innerHTML = localStorage.getItem("lastname");localStorage
的值也可以和cookies
一样直接设置:1
2
3
4// store
localStorage.lastname = "Smith";
// retrieve
document.getElementById("result").innerHTML = localStorage.lastname;localStorage.removeItem("name");
删除1
localStorage.removeItem("lastname");
localStorage.clear()
清空
注意:
localStorage
的存储形式是字符串,但它存储的内容不限于字符串,也可以是数组、图片、JSON、样式、脚本…(只要是能序列化成字符串的内容都可以存储)- 在本页面操作
localStorage
不会触发storage
事件,但是别的页面会触发storage
事件- IE9的
localStorage
不支持本地文件,需要将项目部署到服务器才能支持
sessionStorage
sessionStorage
和localStorage
类似,区别在于它只用来存储会话的数据,当会话结束时(浏览器页面关闭时),数据就会被删除掉,如果页面没有关闭,此时刷新页面或进入同源的另一个页面,数据仍然存在。
需要注意的是,打开一个新的标签或窗口时会在顶级浏览上下文中初始化一个新的会话,这点和session cookies
的运行机制是不一样的。
sessionStorage
的使用方法和localStorage
一致。
Web SQL
Web SQL是浏览器端的关系数据库,它并不是HTML5规范的一部分,而是一个独立的规范,通过SQL语句访问数据库。但在2010年W3C宣布放弃更新Web SQL。
尽管不会再更新了,但还是有一部分浏览器支持Web SQL,我们简单看一看它的使用方法,在遇到使用Web SQL的时候不至于完全不了解。
支持情况
目前,最新版的Safari, Chrome和Opeara都支持Web SQL。
核心方法
Web SQL有三大核心方法:
openDatabase
- 创建一个新的数据库对象(可以通过使用已有数据库,也可以创建新数据库)transaction
- 这个方法允许我们创建一个事务,基于事务来提交或者回滚executeSql
- 执行实际的SQL请求
创建数据库
1 | let db = openDatabase("mydb", "1.0", "Test DB", 2*1024*1024, fn); |
数据库被创建完毕时,第5个参数对应的回调函数会被触发,如果没有设置第五个参数,数据库也能够被创建。
执行请求
database.transaction()
函数用来执行请求。这个函数接受一个函数参数,用来指明需要执行的内容:
1 | let db = openDatabase("mydb", "1.0", "Test DB", 2*1024*1024); |
上述代码会在’mydb’数据库中创建一个名叫LOGS的表。
插入数据
我们可以通过简单的SQL语句为数据库插入数据:
1 | let db = openDatabase("mydb", "1.0", "Test DB", 2*1024*1024); |
我们也可以通过动态数据来操作数据库:
1 | let db = openDatabase("mydb", "1.0", "Test DB", 2*1024*1024); |
这里的e_id
和e_log
都是外部变量,executeSql
方法会遍历数组变量中的参数赋给?
。
读取数据
1 | db.transaction(function(tx) { |
IndexedDB
IndexedDB是一个在用户端存储包括文件和二进制数据在内的结构化数据的低级API。它使用索引来实现高性能的数据搜索。由于网页存储对于较少量的数据存储有用,但对于更大量的结构化数据来说不太适用,IndexedDB提供了一个解决方案。
低级API VS 高级API:
没找到官方的解释为什么说IndexedDB是低级API。找到一些比较低级API和高级API的官方文章,大体意思如下:
低级API(low-level api)指原生API,高级API是通过封装低级API来的。
低级API用于管理用户自定义的硬件事件,它为有经验的程序员或工具开发者提供深度评测和控制接口。由于低级API更为底层,所以使用低级API能够提高效率。
IndexedDB与基于SQL的关系型数据库类似,它是一个事务型数据库系统。不同的是,基于SQL的关系型数据库使用固定列表,IndexedDB是基于JavaScript的基于对象的数据库,它允许用户通过一个键(key)来存储和检索对象。所有支持结构化克隆算法的对象都能够被存储到数据库中。
IndexedDB可以将数据长期存储在用户的浏览器中,而且在无网络的情况下也可以访问,所以使用IndexedDB的应用在离线状态下也可以使用。IndexedDB比较适用的场景包括:
- 需要存储大量的数据(如图书馆租赁系统中存储DVD的目录)
- 不需要长期连接网络的应用(如事件清单、记事本、电子邮箱客户端)
特征
IndexedDB数据库通过键值对存储
IndexedDB数据库通过键值对(key-value pairs)的方式来存储数据。数据的值可以是负责的结构化对象,键可以是这些对象的属性。用户可以用对象的任意属性作为索引来实现快速查找。键也可以是二进制对象。
IndexedDB是事务模式的数据库
IndexedDB数据库的所有操作都是通过事务来完成。IndexedDB API提供包括索引、表、指针等多种对象,但这些对象全都通过相应的事务来实现功能。事务有生命周期,在生命周期之后使用会报错。
IndexedDB API基本上是异步的
IndexedDB不通过return语句返回数据,而是需要提供回调函数来接受数据。执行API时,向数据库发送操作请求,操作完成时,数据库会以DOM事件的方式通知用户。
“请求”无处不在
每一个请求都包含
onsuccess
和onerror
事件属性。IndexedDB是面向对象的
操作
初始化数据库
IndexedDB
在不同的浏览器中需要添加前缀,可以用以下代码来实现统一。
1 | window.indexdDB = window.indexdDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB; |
但使用前缀的方法还是会造成一些BUG,或者功能实现不完整,这样会造成一些不太好的用户体验。还是建议明确告知客户有些浏览器并不支持IndexedDB。
1 | if(!window.indexedDB) { |
打开数据库
1 | let request = window.indexedDB.open("mydb", 3); |
IndexedDB使用数据库是通过请求来实现的,它并不马上打开数据库或者马上开始一个事务,发送打开请求会返回一个IDBOpenDBRequest
对象,对象包含了请求成功的result
值和请求失败的error
值。IndexedDB中的大部分异步函数都以这样的机制运行——返回一个包含成功和错误值IDBRequest
对象。open
函数返回的结果是一个IDBDatabase
实例。
请求中传入的第二个参数是数据库的版本。数据库的版本决定了数据库的架构(包括数据库中存储的对象和它们的结构)。
生成处理函数
1 | let db; |
构建数据库
1 | request.onupgradeneeded = function(e) { |
IndexedDB没有表的概念,而是objectStore,一个数据库可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型的数据。
我们可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。
选择键的类型不同,objectStore可以存储的数据结构也有差异。
增加数据
1 | let transaction = db.transaction(["customers"], "readwirte"); |
删除数据
1 | let request = db.objectStore("customers").delete(value); |
参考: