You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// In the following line, you should include the prefixes of implementations you want to test.window.indexedDB=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;// DON'T use "var indexedDB = ..." if you're not in a function.// Moreover, you may need references to some window.IDB* objects:window.IDBTransaction=window.IDBTransaction||window.webkitIDBTransaction||window.msIDBTransaction;window.IDBKeyRange=window.IDBKeyRange||window.webkitIDBKeyRange||window.msIDBKeyRange;// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)
来自中外各大名宿的吐槽,IndexedDB的API是出了名的膈应人。就比如说新建一个数据库,为啥我要给它取名叫request而不是idb之类的。事实上,对IndexedDB来说,新建数据库是一个request请求,用MDN的原话是,IndexedDB uses a lot of requests。通过这些请求,它能够获取到相应的DOM事件,从而判断该操作是成功了还是失败了。同时,这些请求也有readyState,result和errorCode等一系列属性。这怎么看都像是一个XMLHTTPRequest对象,简直不能再坑了。
// All keys ≤ x varr1=IDBKeyRange.upperBound(x);// All keys < x varr2=IDBKeyRange.upperBound(x,true);// All keys ≥ y varr3=IDBKeyRange.lowerBound(y);// All keys > y varr4=IDBKeyRange.lowerBound(y,true);// All keys ≥ x && ≤ y varr5=IDBKeyRange.bound(x,y);// All keys > x &&< y varr6=IDBKeyRange.bound(x,y,true,true);// All keys > x && ≤ y varr7=IDBKeyRange.bound(x,y,true,false);// All keys ≥ x &&< y varr8=IDBKeyRange.bound(x,y,false,true);// The key = z varr9=IDBKeyRange.only(z);
想要构建离线应用,除了使用service worker,另一个绕不开的话题便是IndexedDB。
IndexedDB是浏览器端的一个基于键值对存储的事务型数据库。为什么要用它,因为想要做到在离线情况下展示数据,数据的持久化是离线应用绕不过去的一个坎。以前使用的是Web SQL,不过它已经被废弃掉了,所以never mind。什么,你说localstorage?确实有很多人会使用localstorage来存储数据,但是相比IndexedDB,它存在很大的不足,原因有三:
localstorage 存储有大小限制,限制5MB,不能存储大量数据,尤其是带有结构的数据。
没有查询语句,没有schema,基本上没有任何有关数据库的操作。每次的写入和写出都要字符串化和对象化,何其麻烦。所以在处理带结构的大型数据上基本毫无扩展性。
最关键的一点是,localstorage的API是同步的,这就意味着它会阻塞DOM操作。并且很多时候,离线应用的数据操作需要在service worker中进行,service worker只接受异步的API,所以相较而言,IndexedDB是更好的选择。
下面这张表摘自张鑫旭的博文,改装了一下,可以快速了解IndexeDB的一些基础特性。
也许,上表中说到的一些概念你还不是很懂。嘿,您先别急,先坐下,且听我慢慢给您说。
Q1:什么是NoSQL数据库?
A1:非关系型数据库,其中的一大类便是通过键值(key-value)存储数据。IndexedDB便是属于这一类。
Q2:什么是事务?
A2:指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。它有以下四点特性:
Q3:Cursor是干嘛用的?
A3:cursor即游标,类似于现实中的游标,一个刻度表示一行数据,游标就是尺子上的一片区域,想要获得数据库一行一行的数据,我们可以遍历这个游标就好了。
前菜上的差不多了,现在进入我们的正餐部分。
如何使用IndexedDB?
使用IndexedDB其实还蛮简单的,你只需要做两件事:
创建或打开一个数据库
创建一个Object Store对象仓库(它是IndexedDB存储数据的机制,习惯了关系型数据库的同学可以把它想象成一张表)
遵循上面两步,我们便可以开始愉快的使用IndexedDB了。代码如下:
好吧,我撒谎了,从代码上看,使用IndexedDB并不是那么简单啊,这还是在我没有考虑兼容性的情况下,而忽略了以下这么一大段代码。
来自中外各大名宿的吐槽,IndexedDB的API是出了名的膈应人。就比如说新建一个数据库,为啥我要给它取名叫request而不是idb之类的。事实上,对IndexedDB来说,新建数据库是一个request请求,用MDN的原话是,
IndexedDB uses a lot of requests
。通过这些请求,它能够获取到相应的DOM事件,从而判断该操作是成功了还是失败了。同时,这些请求也有readyState,result和errorCode等一系列属性。这怎么看都像是一个XMLHTTPRequest对象,简直不能再坑了。吐槽归吐槽,我们还是认真看一下上一段代码做了什么。在连接数据库后,我们通过createObjectStore方法新建了三个对象仓储,第一个参数即为仓储名,第二个参数即为配置项,包含两个属性:1. keyPath,2. autoIncrement。keyPath用于指定对象的键,如果未指定,则对象的创建使用的是out-of-line keys;指定了,则使用in-line keys。至于什么是out-of-line keys和in-line keys,我们通过一图流来进行详细的说明。
可以这么理解,out-of-line keys即为单独生成的一个key,可能需要我们自己指定。而in-line keys则是指定对象的一个属性作为key值,由数据库自动绑定。
至于autoIncrement属性,可以看成一个key generator,自动生成key值。一般来说,keyPath和autoIncrement属性只要使用一个就够了,如果两个同时使用,表示键名为递增的整数,且对象不得缺少指定属性。
当然,除了使用key存储对象,也可以为对象指定index。就像上面代码中的createIndex做的那样,我们依然通过一图流来说明key和index的区别。
可以看到,两者其实是同一份数据,只是由不同的属性索引,当需要检索某一特定属性的数据时,index格外有用。
下面讲讲如何进行数据库的CRUD操作,毕竟这才是我们真正关心的。
执行IndexedDB的CRUD操作只需要如下五步:
1. 添加数据
2. 更新数据
3. 删除数据
4. 读取数据
读取操作有那么点不同,因为它会新建一个request,读取数据在request的回调中。
5. 遍历数据
get()和getAll()可以获取单个数据或全部数据,但如果想进行更精细的读取操作,比如读取3-20范围的数据,则需要用到cursor及IDBKeyRange两个对象了。
索引的有用之处,在于可以指定读取数据的范围
IDBKeyRange对象的作用则是生成一个表示范围的Range对象。它的生成方法有四种
下面的代码直接摘自阮一峰老师的文章,仅供参考
通过IDBKeyRange,结合cursor,便可以实现在一定范围内读取数据的操作了。
结语
终于把IndexedDB的API给走了一遍,基本上涵盖了我们日常开发的大部分操作,当然还有一部分API可以直接从MDN上查阅。可以看到,这些API不可谓不繁琐,如果直接使用这些API,估计你们不是累死就是被气死。
正所谓哪里有压迫哪里就有反抗,我们的Jake Archibald大神在官方的基础上封装了一个Promise风格的库--idb,可以方便开发者们按照现代JavaScript的方式使用IndexedDB。这里有一篇文章便是基于这个库来介绍IndexedDB的,写的相当不错。
下面这行代码大概展示了使用idb来写出promise及async风格的代码,来源于medium。
感兴趣的同学也可以看看这个简单的使用idb实现的todoList。
以上,XD。
by zhangxueai@corp.netease.com
The text was updated successfully, but these errors were encountered: