在前一个阶段的工做中,项目组要开发一个平台,为了作出更好的用户体验,实现快速、高质量的交互,从而更快获得用户的反馈,要求在前端把数据存储起来,以后我去研究了下如今比较流行的前端存储数据库,找到了indexedDB,因而便对indexedDB作了一个较为深刻的探索,此文就是记录探索过程的一些心得体会。前端
在使用一个技术以前,先搞清楚它是什么,这对你的理解很重要,从DB就能够看出,它确定是一个数据库,而说到数据库,有两种不一样类型的数据库,就是关系型数据库和非关系型数据库,关系型数据库如Mysql、Oracle等将数据存储在表中,而非关系型数据库如Redis、MongoDB等将数据集做为个体对象存储。indexedDB就是一个非关系型数据库,它不须要你去写一些特定的sql语句来对数据库进行操做,由于它是nosql的,数据形式使用的是json,web
也许熟悉前端存储的会说,不是有了LocalStorage和Cookies吗?为何还要推出indexedDB呢?其实对于在浏览器里存储数据,你可使用cookies或local storage,但它们都是比较简单的技术,而IndexedDB提供了相似数据库风格的数据存储和使用方式。ajax
首先说说Cookies,英文直接翻译过来就是小甜点,听起来很好吃,实际上并非,每次HTTP接受和发送都会传递Cookies数据,它会占用额外的流量。例如,若是你有一个10KB的Cookies数据,发送10次请求,那么,总计就会有100KB的数据在网络上传输。Cookies只能是字符串。浏览器里存储Cookies的空间有限,不少用户禁止浏览器使用Cookies。因此,Cookies只能用来存储小量的非关键的数据。sql
其次说说LocalStorage,LocalStorage是用key-value键值模式存储数据,但跟IndexedDB不同的是,它的数据并非按对象形式存储。它存储的数据都是字符串形式。若是你想让LocalStorage存储对象,你须要借助JSON.stringify()能将对象变成字符串形式,再用JSON.parse()将字符串还原成对象。但若是要存储大量的复杂的数据,这并非一种很好的方案。毕竟,localstorage就是专门为小数量数据设计的,因此它的api设计为同步的。而IndexedDB很适合存储大量数据,它的API是异步调用的。IndexedDB使用索引存储数据,各类数据库操做放在事务中执行。IndexedDB甚至还支持简单的数据类型。IndexedDB比localstorage强大得多,但它的API也相对复杂。对于简单的数据,你应该继续使用localstorage,但当你但愿存储大量数据时,IndexedDB会明显的更适合,IndexedDB能提供你更为复杂的查询数据的方式。数据库
1.对象仓库json
有了数据库后咱们天然但愿建立一个表用来存储数据,但indexedDB中没有表的概念,而是objectStore,一个数据库中能够包含多个objectStore,objectStore是一个灵活的数据结构,能够存放多种类型数据。也就是说一个objectStore至关于一张表,里面存储的每条数据和一个键相关联。咱们可使用每条记录中的某个指定字段做为键值(keyPath),也可使用自动生成的递增数字做为键值(keyGenerator),也能够不指定。选择键的类型不一样,objectStore能够存储的数据结构也有差别。api
键类型数组 |
存储数据浏览器 |
不使用cookie |
任意值,可是没添加一条数据的时候须要指定键参数 |
keyPath |
任意值,可是没添加一条数据的时候须要指定键参数 |
keyGenerator |
任意值 |
都使用 |
Javascript对象,若是对象中有keyPath指定的属性则不生成新的键值,若是没有自动生成递增键值,填充keyPath指定属性 |
如上图,有一个用于保存person的object Store,这个仓库的键就是person的ID值。
2. 事务性
在indexedDB中,每个对数据库操做是在一个事务的上下文中执行的。事务范围一次影响一个或多个object stores,你经过传入一个object store名字的数组到建立事务范围的函数来定义。例如:db.transaction(storeName, 'readwrite'),建立事务的第二个参数是事务模式。当请求一个事务时,必须决定是按照只读仍是读写模式请求访问。
3. 基于请求
对indexedDB数据库的每次操做,描述为经过一个请求打开数据库,访问一个object store,再继续。IndexedDB API天生是基于请求的,这也是API异步本性指示。对于你在数据库执行的每次操做,你必须首先为这个操做建立一个请求。当请求完成,你能够响应由请求结果产生的事件和错误。
4. 异步
在IndexedDB大部分操做并非咱们经常使用的调用方法,返回结果的模式,而是请求—响应的模式,所谓异步API是指并非这条指令执行完毕,咱们就可使用request.result来获取indexedDB对象了,就像使用ajax同样,语句执行完并不表明已经获取到了对象,因此咱们通常在其回调函数中处理。
IndexedDB 鼓励使用的基本模式以下所示:
接下来若是想要理解indexedDB具体怎么玩,最好的方法就是建立一个简单的web应用:把人的姓名、电话、地址存储在IndexedDB里。IndexedDB里提供了简单的增、删、改、查接口,界面以下:
1.打开数据库
a) 首先,你须要知道你的浏览器是否支持IndexedDB。
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB; if(!indexedDB) { console.log("你的浏览器不支持IndexedDB"); }
b) 建立请求打开indexedDB:一旦你的浏览器支持IndexedDB,咱们就能够打开它。你不能直接打开IndexedDB数据库。IndexedDB须要你建立一个请求来打开它。
var request = indexedDB.open(name, version);
第一个参数是数据库的名称,第二个参数是数据库的版本号。版本号能够在升级数据库时用来调整数据库结构和数据。但你增长数据库版本号时,会触发onupgradeneeded事件,这时可能会出现成功、失败和阻止事件三种状况:
request.onerror = function(e) { console.log(e.currentTarget.error.message); }; request.onsuccess = function(e) { myDB.db = e.target.result; console.log('成功打开DB'); }; request.onupgradeneeded = function(e) { var db = e.target.result; if (!db.objectStoreNames.contains('person')) { console.log("我须要建立一个新的存储对象"); //若是表格不存在,建立一个新的表格(keyPath,主键 ; autoIncrement,是否自增),会返回一个对象(objectStore) var objectStore = db.createObjectStore('person', { keyPath: "id", autoIncrement: true }); //指定能够被索引的字段,unique字段是否惟一 objectStore.createIndex("name", "name", { unique: false }); objectStore.createIndex("phone", "phone", { unique: false }); } console.log('数据库版本更改成: ' + version); };
onupgradeneeded事件在第一次打开页面初始化数据库时会被调用,或在当有版本号变化时。因此,你应该在onupgradeneeded函数里建立你的存储数据。若是没有版本号变化,并且页面以前被打开过,你会得到一个onsuccess事件。
2. 添加数据
a) 首先须要建立一个事务,并要求具备读写权限
var transaction = db.transaction(storeName, 'readwrite');
b) 获取objectStore,再调用add方法添加数据
var store = transaction.objectStore(storeName); var request = store.get(key); request.onsuccess = function(e) { data = e.target.result; console.log(student.name); };
3.删除数据
删除跟新增同样,须要建立事务,而后调用删除接口,经过key删除对象。
var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); store.delete(key);
4.查找数据
a) 按key查找
开启事务,获取objectStore,调用往get()方法,往方法里传入对象的key值,取出相应的对象
var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); var request = store.get(key); request.onsuccess = function(e) { data = e.target.result; console.log(student.name); };
b) 使用索引查找
咱们能够在建立object store的时候指明索引,使用object store的createIndex建立索引,方法有三个参数:索引名称、索引属性字段名、索引属性值是否惟一。
objectStore.createIndex("name", "name", { unique: false });
如上代码中,咱们建好了name索引,就能够用该索引来进行查询了:
var transaction = db.transaction(storeName); var store = transaction.objectStore(storeName); var index = store.index(search_index); index.get(value).onsuccess = function(e) { data = e.target.result; console.log(student.id); }
c) 游标遍历数据
对数据库熟悉的同窗很好理解游标的做用,有了数据库object store的游标,咱们就能够利用游标遍历object store了。
var transaction = db.transaction(storeName); var store = transaction.objectStore(storeName); var request = store.openCursor();//打开游标 var dataList = new Array(); var i = 0; request.onsuccess = function(e) { var cursor = e.target.result; if (cursor) { console.log(cursor.key); dataList[i] = cursor.value; console.log(dataList[i].name); i++; cursor.continue(); } data = dataList; };
4.更新对象
更新对象,首先要把它取出来,修改,而后再放回去。
var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); var request = store.get(key); request.onsuccess = function(e) { var data = e.target.result; for (a in newData) { //除了keypath以外 data.a = newData.a; } store.put(data); };
5.关闭与删除数据库
关闭数据库能够直接调用数据库对象的close方法
function closeDB(db) { db.close(); }
删除数据库使用数据库对象的deleteDatabase方法
function deleteDB(name) { indexedDB.deleteDatabase(name); }
以上就是indexedDB的一些基本概念以及使用,因为篇幅缘由,还有一些更深刻的细节没有介绍,好比indexedDB的游标结合索引,发挥其真正的优点,有兴趣的小伙伴能够继续深刻研究,还有就是要注意浏览器的支持问题,IE9以及更早的版本并不支持,火狐和谷歌浏览器没有问题,推荐使用,文章若是纰漏或者不足,欢迎指正~