在 浏览器数据库 IndexedDB 简明教程 ( 三 ) - 能用否 ? 中我们学习了如何判断浏览器是否支持 IndexedDB
,同时也阐述了针对不支持的浏览器的一种解决方案。我并没有推荐使用 module-aware
的 「 合约模式」 代替 「 插件模式 」 ,只是觉得这种模式非常好,业务根本没必要关系底层如何实现
打开 ( open ) 或 创建 ( create ) 或 打开即创建
本章节,我们继续学习 IndexedDB
,使用 IndexedDB
前最终的一件事就是确保数据库是否存在。
当检查完数据库是否存在后,就两件事,存在则打开,不存在则创建。这个道理很简单,大家都懂。
很多有点古老的数据库,都为这两个操作提供了两套 API,而且打开一个数据库之前必须先用创建数据库的 API 创建。比如 MySQL 提供了 create database
语句用于创建数据库,而提供了 use
语句用于打开数据库
但是,一些最新的数据库系统,例如 MongoDB 和 Redis 则只提供了一套 API。即用于创建又用于打开,模式类似于 「 如果存在,则直接打开,不存在则先创建再打开 」
然后,你知道的,我们要讲解的 IndexedDB
也使用的是最新的这种 「 打开即创建 」 的方法
window.indexedDB.open()
window.indexedDB
提供了一个方法 open()
用于打开一个已经存在的数据库,并返回一个 IDBOpenDBRequest
的对象
indexedDB.open()
方法是异步的,永远都会返回一个 IDBOpenDBRequest
的对象
该方法的原型为
IDBOpenDBRequest open(database,version)
-
参数
database
是一个字符串,指定了要打开的数据库名称。如果指定的数据库不存在,则默认会自动新创建一个,然后在打开 -
参数
version
则是一个整数,用于指定要打开的数据库的版本。如果省略该参数,则会自动打开数据库的最新版本,如果数据库不存在,则默认值为1
indexedDB.open()
方法的返回值是一个 IDBOpenDBRequest
的实例。无论是否成功打开,返回的都是 IDBOpenDBRequest
的实例
范例
例如下面的语句,用于在当前域名下创建一个 IndexedDB
数据库 demo
,并且使用默认的版本号 1
const req = window.indexedDB.open('demo'); console.log(req);
输出结果如下
IDBOpenDBRequest {onblocked: null, onupgradeneeded: null, result: IDBDatabase, error: null, source: null, …}
IDBOpenDBRequest
当我们展开 IDBOpenDBRequest
对象的实例 re1
时,可以看到该对象有以下属性和方法
IDBOpenDBRequest { error:null, onblocked : null, onerror : null, onsuccess : null, onupgradeneeded : null readyState: "done" result : IDBDatabase { name : "demo" objectStoreNames : DOMStringList {length: 0} onabort :null onclose :null onerror :null onversionchange :null version :1 __proto__ : IDBDatabase } source : null, transaction : null, __proto__ : IDBOpenDBRequest }
这个 IDBOpenDBRequest
真的是很简单,每个方法每个属性都简明扼要
其中最终要的是三个事件属性 error
, success
, upgradeneeded
分别用于在 打开失败或升级失败
、打开成功
和 版本升级成功
后的回调
如果你熟悉 Node.js,你会对这种事件回调方法非常的熟悉
-
事件
error
事件
error
用于指定数据库打开失败或升级失败
时候的回调函数,结合上面的req
对象,使用方法一般如下request.onerror = function (event) { console.log('打开数据库失败'); };
-
事件
success
事件
success
用于指定数据库打开成功
时候的回调函数,用法一般如下// 先指定一个全局的变量用于存储数据库对象实例 var db; req.onsuccess = function (event) { db = event.target.result; console.log('数据库成功打开'); };
关于
event.target.result
对象,我们稍后会学习到 -
事件
upgradeneeded
如果
open()
方法的参数version
所指定的版本号大于数据库的实际版本号,则会发生数据库升级事件升级升级有可能成功,也有可能失败
但是,有一点很重要,就是如果检测到需要升级,那么会先升级,然后再打开
- 如果是失败则会触发事件
error
- 如果成功,则会先触发
upgradeneeded
然后再触发success
- 如果版本号相同,则不会触发升级,也就不会触发升级事件
upgradeneeded
该事件的使用方法一般如下
request.onupgradeneeded = function (event) { let db2 = event.target.result; }
注意:虽然
onupgradeneeded
事件的参数event
也会返回一个数据库对象IDBDatabase
,但该对象只是表示升级成功的数据库对象,并不一定表示之后的打开操作中会一定成功。所以一般情况下,不建议将event.target.result
赋值给全局数据库变量 - 如果是失败则会触发事件
范例
了解了这三个属性,现在我们就可以写一个完整的打开数据库的代码了
let db; const req = window.indexedDB.open('demo'); req.onerror = function (event) { console.log('打开数据库失败'); }; req.onsuccess = function (event) { db = event.target.result; console.log('打开数据库成功'); }; req.onupgradeneeded = function (event) { console.log(event.target); console.log('升级成功'); }
运行结果为
打开数据库成功
IDBDatabase 对象
我们可以看到,对于数据库升级成功和打开成功,都会返回一个 IDBDatabase
对象的实例,它表示的就是我们要打开的数据库,我们一起来看看这个数据库实例有什么属性吧
运行下面的代码
const req = window.indexedDB.open('demo',1); req.onsuccess = function (event) { console.log(event.target.result); };
将输出结果展开后,得到
IDBDatabase { name : "demo" objectStoreNames : DOMStringList {length: 0} onabort :null onclose :null onerror :null onversionchange :null version :1 __proto__ : IDBDatabase }
IDBDatabase 对象也有很多事件属性,但这些事件属性我们以后会介绍,我们就来看看对于数据库来说的两个最重要的属性
name : "demo"
用于表示当前打开的或升级的数据库的名称version :1
用于表示当前打开的或升级成功后的数据库的版本号
这两个属性,我们一般情况下会在 Web 开发过程中传回给服务器,用于服务器确定要如何升级
结束语
本章节的内容有点长,希望打开能消化得了。而对于我们未介绍的 IndexedDB
版本升级机制,我们将在下一章节中介绍