该笔记的内容主要来自本人在学习渡一课程的配套资料和个人总结而成
IndexedDB 本文主要包含以下内容:
IndexedDB 简介
IndexedDB 重要概念
IndexedDB 实操
操作数据库
插入数据
读取数据
更新数据
删除数据
IndexedDB 简介随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端 ,这样可以减少从服务器获取数据,直接从本地获取数据。
现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过 4KB ,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。
MDN 官网是这样解释 IndexedDB 的:
IndexedDB 是一种底层 API ,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs ))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。
通俗地说,IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引 。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。
下表罗列出了几种常见的客户端存储方式的对比:
会话期 Cookie
持久性 Cookie
sessionStorage
localStorage
IndexedDB
WebSQL
存储大小
4kb
4kb
2.5~10MB
2.5~10MB
>250MB
已废弃
失效时间
浏览器关闭自动清除
设置过期时间,到期后清除
浏览器关闭后清除
永久保存(除非手动清除)
手动更新或删除
已废弃
IndexedDB 具有以下特点。
键值对储存: IndexedDB 内部采用对象仓库( object store )存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以“键值对 ”的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
异步 :**IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。**异步设计是为了防止大量数据的读写,拖慢网页的表现。
支持事务: IndexedDB 支持事务( transaction ) ,这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。这和 MySQL 等数据库的事务类似。
同源限制: IndexedDB 受到同源限制 ,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
储存空间大: 这是 IndexedDB 最显著的特点之一 。IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB ,甚至没有上限。
支持二进制储存: IndexedDB 不仅可以储存字符串,还可以储存二进制数据( ArrayBuffer 对象和 Blob 对象)。
IndexedDB 主要使用在于客户端需要存储大量的数据的场景下:
IndexedDB 重要概念在正式开始之前,我们先来介绍一下 IndexedDB 里面一些重要的概念。
IndexedDB 是一个比较复杂的 API ,涉及不少概念。它把不同的实体,抽象成一个个对象接口。学习这个 API ,就是学习它的各种对象接口。
数据库:IDBDatabase 对象
对象仓库:IDBObjectStore 对象
索引:IDBIndex 对象
事务:IDBTransaction 对象
操作请求:IDBRequest 对象
指针:IDBCursor 对象
主键集合:IDBKeyRange 对象
下面是一些主要的概念。
(1)数据库
数据库是一系列相关数据的容器。每个域名(严格的说,是协议 + 域名 + 端口)都可以新建任意多个数据库。
IndexedDB 数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。
(2)对象仓库
每个数据库包含若干个对象仓库( object store )。它类似于关系型数据库的表格。
(3)数据记录
对象仓库保存的是数据记录。**每条记录类似于关系型数据库的行,但是只有主键和数据体两部分。**主键用来建立默认的索引,必须是不同的,否则会报错。主键可以是数据记录里面的一个属性,也可以指定为一个递增的整数编号。
上面的对象中,id 属性可以当作主键。
数据体可以是任意数据类型,不限于对象。
(4)索引
为了加速数据的检索 ,可以在对象仓库里面,为不同的属性建立索引。
在关系型数据库当中也有索引的概念,我们可以给对应的表字段添加索引,以便加快查找速率。在 IndexedDB 中同样有索引,我们可以在创建 store 的时候同时创建索引,在后续对 store 进行查询的时候即可通过索引来筛选 ,给某个字段添加索引后,在后续插入数据的过成功,索引字段便不能为空。
(5)事务
**数据记录的读写和删改,都要通过事务完成。**事务对象提供 error、abort 和 complete 三个事件,用来监听操作结果。
(6)指针(游标) 游标是 IndexedDB 数据库新的概念,大家可以把游标想象为一个指针,比如我们要查询满足某一条件的所有数据时,就需要用到游标,我们让游标一行一行的往下走,游标走到的地方便会返回这一行数据,此时我们便可对此行数据进行判断,是否满足条件。
IndexedDB 实操IndexedDB 所有针对仓库的操作都是基于事务的。
在正式开始之前,我们先创建如下的项目结构:
该项目目录下存在 2 个文件,其中 db.js 是用来封装各种数据库操作的。
操作数据库 首先第一步是创建以及连接数据库。
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 function openDB (dbName, version = 1 ) { return new Promise ((resolve, reject ) => { let db; const request = indexedDB.open (dbName, version); request.onsuccess = function (event ) { db = event.target .result ; console .log ("数据库打开成功" ); resolve (db); }; request.onerror = function (event ) { console .log ("数据库打开失败" ); reject (event); }; request.onupgradeneeded = function (event ) { console .log ("数据库更新" ); db = event.target .result ; let objectStore = db.createObjectStore ("stu" , { keyPath : "stuId" , autoIncrement : true , }); objectStore.createIndex ("stuId" , "stuId" , { unique : true }); objectStore.createIndex ("stuName" , "stuName" , { unique : false }); objectStore.createIndex ("stuAge" , "stuAge" , { unique : false }); }; }); }
在上面的代码中,我们封装了一个 openDB 的函数,该函数调用 indexedDB.open 方法来尝试打开一个数据库,如果该数据库不存在,就会创建。
indexedDB.open 方法返回一个对象,我们在这个对象上面分别监听了成功、错误以及更新这三个事件。
这里尤其要说一下 upgradeneeded 更新事件。该事件会在数据库发生更新时触发,什么叫做数据库有更新时呢?就是添加或删除对象仓库(表),以及数据库版本号更新的时候。
因为一开始创建数据库时,版本是从无到有,所以也会触发这个事件。
index.html 1 2 3 4 5 6 <body > <script src ="./db.js" > </script > <script > openDB ("stuDB" , 1 ); </script > </body >
在 index.html 文件中,我们引入了 db.js ,然后调用了 openDB 方法,效果如下图所示。
使用完数据库后,建议关闭数据库,以节约资源。
db.js 1 2 3 4 5 6 7 8 function closeDB (db ) { db.close (); console .log ("数据库已关闭" ); }
如果要删除数据库,可以使用 indexDB 的 deleteDatabase 方法即可。
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function deleteDBAll (dbName ) { console .log (dbName); let deleteRequest = indexedDB.deleteDatabase (dbName); deleteRequest.onerror = function (event ) { console .log ("删除失败" ); }; deleteRequest.onsuccess = function (event ) { console .log ("删除成功" ); }; }
插入数据 接下来是插入数据,我们仍然封装一个 addData 方法,代码如下:
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function addData (db, storeName, data ) { let request = db .transaction ([storeName], "readwrite" ) .objectStore (storeName) .add (data); request.onsuccess = function (event ) { console .log ("数据写入成功" ); }; request.onerror = function (event ) { console .log ("数据写入失败" ); }; }
IndexedDB 插入数据需要通过事务 来进行操作,插入的方法也很简单,利用 IndexedDB 提供的 add 方法即可,这里我们同样将插入数据的操作封装成了一个函数,接收三个参数,分别如下:
db :在创建或连接数据库时,返回的 db 实例,需要那个时候保存下来。
storeName :仓库名称(或者表名),在创建或连接数据库时我们就已经创建好了仓库。
data :需要插入的数据,通常是一个对象。
接下来我们在 index.html 中来测试。
1 2 3 4 5 6 7 8 9 10 <body > <script src ="./db.js" > </script > <script > openDB ("stuDB" , 1 ).then ((db ) => { addData (db, "stu" , { stuId : 1 , stuName : "谢杰" , stuAge : 18 }); addData (db, "stu" , { stuId : 2 , stuName : "雅静" , stuAge : 20 }); addData (db, "stu" , { stuId : 3 , stuName : "谢希之" , stuAge : 4 }); }); </script > </body >
效果如下:
注意:插入的数据是一个对象,而且必须包含我们声明的索引键值对。
读取数据 读取数据根据需求的不同有不同的读取方式。
通过主键读取数据 db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 function getDataByKey (db, storeName, key ) { if (!db || !storeName || key === undefined ) { return Promise .reject (new Error ("参数无效" )); } return new Promise ((resolve, reject ) => { let transaction = db.transaction ([storeName], "readonly" ); transaction.oncomplete = function ( ) { console .log ("事务完成" ); }; transaction.onerror = function (event ) { console .error ("事务失败:" , event.target .error ); reject (event.target .error ); }; let objectStore = transaction.objectStore (storeName); let request = objectStore.get (key); request.onsuccess = function (event ) { resolve (request.result ); }; request.onerror = function (event ) { reject (event.target .error ); }; }); }
在仓库对象上面调用 get 方法从而通过主键获取数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <body > <script src ="./db.js" > </script > <script > openDB ("stuDB" , 1 ) .then ((db ) => { addData (db, "stu" , { stuId : 1 , stuName : "谢杰" , stuAge : 18 }); addData (db, "stu" , { stuId : 2 , stuName : "雅静" , stuAge : 20 }); addData (db, "stu" , { stuId : 3 , stuName : "谢希之" , stuAge : 4 }); return getDataByKey (db, "stu" , 2 ); }) .then ((stuInfo ) => { console .log (stuInfo); }); </script > </body >
在 index.html 中进行测试,调用上面封装的 getDataByKey 方法,可以看到返回了主键 stuId 为 2 的学生数据。
读取所有数据 仓库对象也提供了 getAll 方法, 能够查询整张表的数据内容。
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 function getAllData (db, storeName ) { if (!db || !storeName) { return Promise .reject (new Error ("参数无效" )); } return new Promise ((resolve, reject ) => { let transaction = db.transaction ([storeName], "readonly" ); transaction.oncomplete = function ( ) { console .log ("事务完成" ); }; transaction.onerror = function (event ) { console .error ("事务失败:" , event.target .error ); reject (event.target .error ); }; let objectStore = transaction.objectStore (storeName); let request = objectStore.getAll (); request.onsuccess = function (event ) { resolve (request.result ); }; request.onerror = function (event ) { reject (event.target .error ); }; }); }
在 index.html 中调用方法时就不需要再传递第三个参数作为 key 了。
index.html 1 2 3 4 5 6 7 8 9 10 openDB ("stuDB" , 1 ) .then ((db ) => { addData (db, "stu" , { stuId : 1 , stuName : "谢杰" , stuAge : 18 }); addData (db, "stu" , { stuId : 2 , stuName : "雅静" , stuAge : 20 }); addData (db, "stu" , { stuId : 3 , stuName : "谢希之" , stuAge : 4 }); return getAllData (db, "stu" ); }) .then ((stuInfo ) => { console .log (stuInfo); });
通过指针读取数据 还可以通过指针来进行查询,例如:
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function cursorGetData (db, storeName ) { return new Promise ((resolve, reject ) => { let list = []; let store = db .transaction (storeName, "readwrite" ) .objectStore (storeName); let request = store.openCursor (); request.onsuccess = function (event ) { let cursor = event.target .result ; if (cursor) { list.push (cursor.value ); cursor.continue (); } else { resolve (list); } }; }); }
在上面的代码中,我们通过仓库对象的 openCursor
方法开启了一个指针,这个指针会指向数据表的第一条数据,之后指针逐项进行偏移从而遍历整个数据表。
所以每次偏移拿到数据后,我们 push 到 list 数组里面,如果某一次没有拿到数据,说明已经读取完了所有的数据,那么我们就返回 list 数组。
indx.html 1 2 3 4 5 6 7 8 9 10 openDB ("stuDB" , 1 ) .then ((db ) => { addData (db, "stu" , { stuId : 1 , stuName : "谢杰" , stuAge : 18 }); addData (db, "stu" , { stuId : 2 , stuName : "雅静" , stuAge : 20 }); addData (db, "stu" , { stuId : 3 , stuName : "谢希之" , stuAge : 4 }); return cursorGetData (db, "stu" ); }) .then ((stuInfo ) => { console .log (stuInfo); });
目前为止,我们的精准查询只能通过主键来进行查询。但是更多的场景是我们压根儿就不知道某一条数据的主键。例如我们要查询学生姓名为“张三”的学生数据,对于我们来讲,我们知道的信息只有学生姓名“张三”。
此时我们就可以通过索引来查询数据。
通过索引来读取数据 db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function getDataByIndex (db, storeName, indexName, indexValue ) { return new Promise ((resolve, reject ) => { let store = db .transaction (storeName, "readwrite" ) .objectStore (storeName); let request = store.index (indexName).get (indexValue); request.onerror = function (event ) { reject (event.target .error ); }; request.onsuccess = function (event ) { let result = event.target .result ; resolve (result); }; }); }
在上面的方法中,我们通过仓库对象的 index 方法传入了索引名称,然后链式调用 get 方法传入索引的值来得到最终的查询结果。
index.html 1 2 3 4 5 6 7 8 openDB ("stuDB" , 1 ) .then ((db ) => { addData (db, "stu" , { stuId : 4 , stuName : "牛牛" , stuAge : 4 }); return getDataByIndex (db, "stu" , "stuAge" , 4 ); }) .then ((stuInfo ) => { console .log (stuInfo); });
在 index.html 中我们新增了一条数据,年龄也为 4 ,当前的数据库表信息如下:
但是很奇怪的是我们查询出来的数据却只有第一条符合要求的。
如果我们想要查询出索引中满足某些条件的所有数据,可以将索引和游标结合起来。
结合索引和游标读取所有满足条件的数据 db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 function cursorGetDataByIndex (db, storeName, indexName, indexValue ) { return new Promise ((resolve, reject ) => { let list = []; let store = db .transaction (storeName, "readwrite" ) .objectStore (storeName); let request = store .index (indexName) .openCursor (IDBKeyRange .only (indexValue)); request.onsuccess = function (event ) { let cursor = event.target .result ; if (cursor) { list.push (cursor.value ); cursor.continue (); } else { resolve (list); } }; request.onerror = function (event ) { reject (event.target .error ); }; }); }
在上面的方法中,我们仍然是使用对象仓库的 index 方法进行索引查询 ,但是之后链式调用的时候不再是使用 get 方法传入索引值,而是调用了 openCursor 来打开一个指针,并且让指针指向满足索引值的数据 ,之后和前面一样,符合要求的数据推入到 list 数组,最后返回 list 数组。
当然,你可能很好奇 IDBKeyRange 的 only 方法是什么意思,除了 only 方法还有其他方法么?
IDBKeyRange 对象代表对象仓库(object store )里面的一组主键。根据这组主键,可以获取对象仓库或索引里面的一组记录。
IDBKeyRange 可以只包含一个值,也可以指定上限和下限。它有四个静态方法,用来指定主键的范围。
IDBKeyRange.lowerBound( ) :指定下限。
IDBKeyRange.upperBound( ) :指定上限。
IDBKeyRange.bound( ) :同时指定上下限。
IDBKeyRange.only( ) :指定只包含一个值。
下面是一些代码实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 let r1 = IDBKeyRange .upperBound (x);let r2 = IDBKeyRange .upperBound (x, true );let r3 = IDBKeyRange .lowerBound (y);let r4 = IDBKeyRange .lowerBound (y, true );let r5 = IDBKeyRange .bound (x, y);let r6 = IDBKeyRange .bound (x, y, true , true );let r7 = IDBKeyRange .bound (x, y, true , false );let r8 = IDBKeyRange .bound (x, y, false , true );let r9 = IDBKeyRange .only (z);
例如我们来查询年龄大于 4 岁的学生,其代码片段如下:
db.js 1 2 3 4 5 6 7 8 9 10 function cursorGetDataByIndex (db, storeName, indexName, indexValue ) { return new Promise ((resolve, reject ) => { ... let request = store .index (indexName) .openCursor (IDBKeyRange .lowerBound (indexValue, true )); ... }) }
利用索引和游标结合查询,我们可以查询出索引值满足我们传入函数值的所有数据对象,而不是只查询出一条数据或者所有数据。
分页查询数据 IndexedDB 分页查询不像 MySQL 分页查询那么简单,没有提供现成的 API ,如 limit 等,所以需要我们自己实现分页。
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 function cursorGetDataByIndexAndPage ( db, storeName, indexName, indexValue, page, pageSize ) { return new Promise ((resolve, reject ) => { let list = []; let counter = 0 ; let isPass = true ; let store = db .transaction (storeName, "readwrite" ) .objectStore (storeName); let request = store .openCursor (); request.onsuccess = function (event ) { let cursor = event.target .result ; if (page > 1 && isPass) { isPass = false ; cursor.advance ((page - 1 ) * pageSize); return ; } if (cursor) { list.push (cursor.value ); counter++; if (counter < pageSize) { cursor.continue (); } else { cursor = null ; resolve (list); } } else { resolve (list); } }; request.onerror = function (event ) { reject (event.target .error ); }; }); }
这里用到了 IndexedDB 的一个 API :advance 。
**该函数可以让我们的游标跳过多少条开始查询。**假如我们的额分页是每页 5 条数据,现在需要查询第 2 页,那么我们就需要跳过前面 5 条数据,从第 6 条数据开始查询,直到计数器等于 5 ,那么我们就关闭游标,结束查询。
下面在 index.html 中进行测试如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <body > <script src ="./db.js" > </script > <script > openDB ("stuDB" , 1 ) .then ((db ) => { addData (db, "stu" , { stuId : 5 , stuName : "张三" , stuAge : 23 }); addData (db, "stu" , { stuId : 6 , stuName : "李四" , stuAge : 24 }); addData (db, "stu" , { stuId : 7 , stuName : "王武" , stuAge : 32 }); addData (db, "stu" , { stuId : 8 , stuName : "刘德华" , stuAge : 34 }); addData (db, "stu" , { stuId : 9 , stuName : "张学友" , stuAge : 28 }); addData (db, "stu" , { stuId : 10 , stuName : "郭富城" , stuAge : 27 }); addData (db, "stu" , { stuId : 11 , stuName : "黎明" , stuAge : 17 }); addData (db, "stu" , { stuId : 12 , stuName : "邓超" , stuAge : 19 }); addData (db, "stu" , { stuId : 13 , stuName : "刘翔" , stuAge : 15 }); addData (db, "stu" , { stuId : 14 , stuName : "洋洋" , stuAge : 12 }); addData (db, "stu" , { stuId : 15 , stuName : "林佳音" , stuAge : 14 }); addData (db, "stu" , { stuId : 16 , stuName : "袁进" , stuAge : 34 }); addData (db, "stu" , { stuId : 17 , stuName : "老闫" , stuAge : 36 }); addData (db, "stu" , { stuId : 18 , stuName : "沈爷" , stuAge : 34 }); return cursorGetDataByIndexAndPage (db, "stu" , "" , "" , 3 , 5 ); }) .then ((stuInfo ) => { console .log (stuInfo); }); </script > </body >
在上面的代码中,我们为了实现分页效果,添加了一些数据。然后查询第 3 页的内容。
查询结果如下:
更新数据 IndexedDB 更新数据较为简单,直接使用 put 方法,值得注意的是如果数据库中没有该条数据,则会默认增加该条数据,否则更新。
有些小伙伴喜欢更新和新增都是用 put 方法,这也是可行的。
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function updateDB (db, storeName, data ) { return new Promise ((resolve, reject ) => { let request = db .transaction ([storeName], "readwrite" ) .objectStore (storeName) .put (data); request.onsuccess = function ( ) { resolve ({ status : true , message : "更新数据成功" , }); }; request.onerror = function ( ) { reject ({ status : false , message : "更新数据失败" , }); }; }); }
在上面的方法中,我们使用仓库对象的 put 方法来修改数据,所以在调用该方法时,需要传入整条数据对象,特别是主键。因为是通过主键来查询到要修改的数据。如果传入的数据没有主键,则是一个新增数据的效果。
index.html 1 2 3 4 5 6 7 openDB ("stuDB" , 1 ) .then ((db ) => { return updateDB (db, "stu" , { stuId : 1 , stuName : "谢杰2" , stuAge : 19 }); }) .then (({ message } ) => { console .log (message); });
效果如下:
删除数据 删除数据这里记录 2 种方式,一个是通过主键 来进行删除。
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function deleteDB (db, storeName, id ) { return new Promise ((resolve, reject ) => { let request = db .transaction ([storeName], "readwrite" ) .objectStore (storeName) .delete (id); request.onsuccess = function ( ) { resolve ({ status : true , message : "删除数据成功" , }); }; request.onerror = function ( ) { reject ({ status : true , message : "删除数据失败" , }); }; }); }
index.html 1 2 3 4 5 6 7 openDB ("stuDB" , 1 ) .then ((db ) => { return deleteDB (db, "stu" , 1 ); }) .then (({ message } ) => { console .log (message); });
执行上面的代码后 stuId 为 1 的学生被删除掉。
有时候我们拿不到主键值,只能只能通过索引值来删除 。通过这种方式,我们可以删除一条数据(索引值唯一)或者所有满足条件的数据(索引值不唯一)。
db.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 function cursorDelete (db, storeName, indexName, indexValue ) { return new Promise ((resolve, reject ) => { let store = db .transaction (storeName, "readwrite" ) .objectStore (storeName); let request = store .index (indexName) .openCursor (IDBKeyRange .only (indexValue)); request.onsuccess = function (event ) { let cursor = event.target .result ; let deleteRequest; if (cursor) { deleteRequest = cursor.delete (); deleteRequest.onsuccess = function ( ) { resolve ({ status : true , message : "游标删除该记录成功" , }); }; deleteRequest.onerror = function ( ) { reject ({ status : false , message : "游标删除该记录失败" , }); }; cursor.continue (); } }; request.onerror = function (event ) { reject (event.target .error ); }; }); }
index.html 1 2 3 4 5 6 7 openDB ("stuDB" , 1 ) .then ((db ) => { return cursorDelete (db, "stu" , "stuName" , "雅静" ); }) .then (({ message } ) => { console .log (message); });
在上面的示例中,我们就删除了所有 stuName 值为 “雅静” 的同学。
以上,就是关于 IndexedDB 的基本操作。
可以看到,在了解了它的几个基本概念后,上手还是比较容易的。
另外由于 IndexedDB 所提供的原生 API 比较复杂,所以现在也出现了基于 IndexedDB 封装的库。例如 Dexie.js 。
该库和 IndexedDB 之间的关系,就类似于 jQuery 和 JavaScript 之间的关系。有兴趣的同学可以自行进行研究,这里就不再做过多的赘述。