首先,我仔细阅读了下资料,终于发现上一章节 浏览器 IndexedDB 简明教程 ( 七 ) - 数据库 ( IDBDatabase ) 方法 说的那个 createObjectStore()
和 deleteObjectStore()
在 onsuccess
事件中会失败的原因
因为,这种可以变更操作,只能在一个事务里调用
事务我们还没讲到,但是目前已知的默认会开启事务的只有一个回调事件,那就是 onupgradeneeded
,所以呢,这两个方法放在 onsuccess
回调中是会失败的
let db; //先删除 window.indexedDB.deleteDatabase('demo') const req = window.indexedDB.open('demo'); req.onerror = function (event) { console.log('打开数据库失败'); }; req.onsuccess = function (event) { console.log('打开数据库成功'); db = event.target.result; // 创建存储对象 `city` 并指定 `city_id` 为主键 db.createObjectStore('city',{keyPath:'city_id'}); // 删除刚刚创建的对象 db.deleteObjectStore('city'); }; req.onupgradeneeded = function (event) { console.log('升级成功'); }
输出结果如下
升级成功 打开数据库成功 Uncaught DOMException: Failed to execute 'createObjectStore' on 'IDBDatabase': The database is not running a version change transaction.
大概的意思就是说数据库没有运行在一个 「 版本变更 」 的事务里,这个版本变更,其实就是 onupgradeneeded
回调,这个,我们有空细细说明吧,因为牵涉到的内容实在太多了
我们本章节的主要内容,就是来讲讲如何 「 判断某个存储对象是否存在 」
DOMStringList
在上一章节的 「 结束语 」 部分,我们说过 「 其实不止删除不存在的存储对象会报错,当存储对象存在时再执行一次创建动作也会失败 」
为了解决这个问题,我们必须在执行删除存储对象动作和创建存储对象动作之前先判断该存储对象是否存在
翻了一圈的 API 文档,发现 IndexedDB 没有提供类似的方法,所以,我们只能从存储对象这个角度入手
在前一章节中,我们知道 IDBDatabase
有一个只读属性 objectStoreNames
,表示当前连接的数据库中的存储对象名称的列表
我们进一步发现,这个 objectStoreNames
的类型竟然是 DOMStringList
。
那 DOMStringList
又是什么呢?
它是 HTML DOM 中的一个返回值类型,是一个 DOMString ( 字符串 ) 列表
DOMStringList
包含了一个属性和两个方法
属性 | 说明 |
---|---|
DOMStringList.length | 字符串列表长度 |
方法 | 说明 |
---|---|
DOMStringList.item(index) | 返回指定索引 ( index ) 处的值 |
DOMStringList.contains( str ) | 判断是否存在某个字符串 |
所以,也就是说,我们可以使用 objectStoreNames.contains()
的相关方法和属性来判断某个存储对象是否存在
IDBDatabase.objectStoreNames.contains()
IDBDatabase.objectStoreNames.contains()
方法可以用来判断某个存储对象是否存在,参数很简单,就是存储对象的名称,例如下面的代码
let db; //先删除 window.indexedDB.deleteDatabase('demo') const req = window.indexedDB.open('demo'); req.onerror = function (event) { console.log('打开数据库失败'); }; req.onsuccess = function (event) { console.log('打开数据库成功'); db = event.target.result; }; req.onupgradeneeded = function (event) { console.log('升级成功'); let db2 = event.target.result; // 如果不存在存储对象 `city` 则创建 if ( ! db2.objectStoreNames.contains('city')) { // 创建存储对象 `city` 并指定 `city_id` 为主键 db2.createObjectStore('city',{keyPath:'city_id'}); } // 如果存在存储对象 `city` 则删除 if ( db2.objectStoreNames.contains('city')) { db2.deleteObjectStore('city'); } }
结束语
我昨天说过一句话,就是 「 翻译不易,维护更难...且行且珍惜 」
一直以来,我也处在是原生态的翻译原文档更好呢还是在原来的文档上加上自己的一些理解更好 ?
我也一直出于徘徊犹豫的边缘,最后,我给自己定的目标是
- 教程和入门序列的的文档,一定要是自己理解的基础上去写出来,或许是 100% 的翻译,或许不是
- API 级别的文档,尽量 100% 原生翻译,比如 「 参考文档 」
但是,要做到这一点非常难,尤其是官方文档会定时的升级,对于那些能拿到官方文档源码还好说,拿不到的,又去哪里找呢?