本文通过对IndexedDB
的使用方法和使用场景进行相关介绍,对常见的问题进行解答。
同时,因为MDN中的相关文档缺乏相关逻辑性,所以不容易理解。本文将通过项目中常见的数据存储和操作需求来进行内容组织。
读者能够通过本文学会在项目中正确的使用IndexedDB
,给应用带来的本地存储能力,并且避免一些常见的问题。
当我们进行一些较大的SPA页面开发时,我们会需要进行一些数据的本地存储。
当数据量不大时,我们可以通过SessionStorage或者LocalStorage来进行存储,但是当数据量较大,或符合一定的规范时,我们可以使用数据库来进行数据的存储。
在浏览器提供的数据库中,共有web sql
和IndexedDB
两种。相较于HTML5已经废弃的web sql
来说,更推荐大家使用IndexedDB
。
下面,我们通过一张图来了解下,IndexedDB整体的结构。
类比sql
型数据库,IndexedDB
中的DB(数据库)就是sql
中的DB,而Object Store(存储空间)
则是数据表
,Item
则等于表中的一条记录
。
现在,我们将其根据IndexedDB
的结构来对其操作进行介绍,能让大家对这个存储空间有一个初步的了解。我们主要介绍:
使用IndexedDB
第一步,就是创建或打开一个数据库。我们使用window.indexedDB.open(DBName)
这个API来打进行操作。具体示例如下:
const request = window.indexedDB.open('test');
request.onupgradeneeded = function (event) {
}
request.onsuccess = function(event) {
//request === event.target;
}
request.onerror = function(event) {}
调用此接口时,如果当前数据库不存在,则会创建一个新的数据库。
当数据库建立连接时,会返回一个IDBOpenDBRequest
对象。
在连接建立成功时,会触发onsuccess
事件,其中函数参数event
的target
属性就是request
对象。
而在数据库创建或者版本更新时,会触发onupgradeneeded
事件。
window.indexedDB.open
的第二个参数即为版本号。在不指定的情况下,默认版本号为1。具体示例如下:
const request = window.indexedDB.open('test', 2);
在需要更新数据库的schema(模式)
时,需要更新版本号。此时我们指定一个高于之前版本的版本号,就会触发onupgradeneeded
事件。类似的,当此数据库不存在时,也会触发此事件并且将版本更新到置顶版本。
我们需要注意的是,版本号是一个Unsigned long long
数字,这意味着它可以是一个非常大的整数。但是,它不能是一个小数,否则它将会被转为最近的整数,同时有可能导致onUpgradeneeded
事件不触发(bug)。
我们使用createObjectStore
来创建一个存储空间。同时,使用createIndex
来创建它的索引。具体示例如下:
var request = window.indexedDB.open('test', 1);
request.onupgradeneeded = function (event) {
var db = event.target.result;
var objectStore = db.createObjectStore('table1', {keyPath: 'id', autoIncrement: true});
objectStore.createIndex('name', 'name', {unique: false});
}
request.onerror = function (event) {
alert("Why didn't you allow my web app to use IndexedDB?!");
};
注:只能在onupgradeneeded
回调函数中创建存储空间,而不能在数据库打开后的success
回调函数中创建。
通过createObjectStore
能够创建一个存储空间。接受两个参数:
customers
。keyPath
值为存储对象的某个属性,这个属性能够在获取存储空间数据的时候当做key值使用。autoIncrement
指定了key
值是否自增(当key值为默认的从1开始到2^53的整数时)。而createIndex
能够给当前的存储空间设置一个索引。它接受三个参数:
unique
的值为true
表示不允许索引值相等。在IndexedDB
中,我们也能够使用事务来进行数据库的操作。事务有三个模式(常量已经弃用):
readOnly
,只读。readwrite
,读写。versionchange
,数据库版本变化。我们创建一个事务时,需要从上面选择一种模式,如果不指定的话,则默认为只读模式。具体示例如下:
const transaction = db.transaction(['customers'], 'readwrite');
事务函数transaction
的第一个参数为需要关联的存储空间,第二个可选参数为事务模式。与上面类似,事务成功时也会触发onsuccess
函数,失败时触发onerror
函数。
事务的操作都是原子性的。
当存储空间初始化完成后,我们可以把数据放入存储空间中。直接调用add
方法就可以将数据放入存储空间内,具体示例如下:
var request = window.indexedDB.open('test', 1);
request.onsuccess = function (event) {
var db = event.target.result;
var transaction = db.transaction(['table1'], 'readwrite');
var objectStore = transaction.objectStore('table1');
var index = objectStore.index('name');
objectStore.add({name: 'a', age: 10});
objectStore.add({name: 'b', age: 20});
}
注:add
方法中的第二个参数key值是指定存储空间中的keyPath
值,如果data
中包含keyPath
值或者此值为自增值,那么可以略去此参数。
当我们需要从存储空间获取数据时,我们可以通过以下的方法:
var request = window.indexedDB.open('test', 1);
request.onsuccess = function (event) {
var db = event.target.result;
var transaction = db.transaction(['table1'], 'readwrite');
var objectStore = transaction.objectStore('table1');
var request = objectStore.get(1);
request.onsuccess = function (event) {
// 对 request.result 做些操作!
console.log(request.result);
};
request.onerror = function (event) {
// 错误处理!
};
}
当你需要遍历整个存储空间中的数据时,你就需要使用到游标。游标使用方法如下:
var request = window.indexedDB.open('test', 1);
request.onsuccess = function (event) {
var db = event.target.result;
var transaction = db.transaction(['table1'], 'readwrite');
var objectStore = transaction.objectStore('table1');
var request = objectStore.openCursor();
request.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
// 使用Object.assign方法是为了避免控制台打印时出错
console.log(Object.assign(cursor.value));
cursor.continue();
}
};
request.onerror = function (event) {
// 错误处理!
};
}
使用游标时有一个需要注意的地方,当游标遍历整个存储空间但是并未找到给定条件的值时,仍然会触发onsuccess
函数。
openCursor
和openKeyCursor
有两个参数:
第一个参数,遍历范围,指定游标的访问范围。该范围通过一个IDBKeyRange
参数的方法来获取。
遍历范围参数具体示例如下:
// 匹配值 key === 1
const singleKeyRange = IDBKeyRange.only(1);
// 匹配值 key >= 1
const lowerBoundKeyRange = IDBKeyRange.lowerBound(1);
// 匹配值 key > 1
const lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, true);
// 匹配值 key < 2
const upperBoundOpenKeyRange = IDBKeyRange.upperBound(2, true);
// 匹配值 key >= 1 && key < 2
const boundKeyRange = IDBKeyRange.bound(1, 2, false, true);
index.openCursor(boundKeyRange).onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
// Do something with the matches.
cursor.continue();
}
};
第二个参数,遍历顺序,指定游标遍历时的顺序和处理相同id(keyPath属性指定字段)重复时的处理方法。改范围通过特定的字符串(IDBCursor
的常量已经弃用)来获取。其中:
next
,从前往后获取所有数据(包括重复数据)prev
,从后往前获取所有数据(包括重复数据)nextunique
,从前往后获取数据(重复数据只取第一条,索引重复即认为重复,下同)prevunique
,从后往前获取数据(重复数据只取第一条)遍历顺序参数具体示例如下:
var request = window.indexedDB.open('test', 1);
request.onsuccess = function (event) {
var db = event.target.result;
var transaction = db.transaction(['table1'], 'readwrite');
var objectStore = transaction.objectStore('table1');
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, false);
var request = objectStore.openCursor(lowerBoundOpenKeyRange, IDBCursor.PREV);
request.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
// 使用Object.assign方法是为了避免控制台打印时出错
console.log(Object.assign(cursor.value));
cursor.continue();
}
};
request.onerror = function (event) {
// 错误处理!
};
}
在前面构建数据库时,我们创建了两个索引。现在我们也可以通过索引来进行数据检索。他的本质还是通过之前获取数据的API来进行,只是将原来使用的keyPath
属性转换成为了索引指定的属性。具体示例如下:
var request = window.indexedDB.open('test', 1);
request.onsuccess = function (event) {
var db = event.target.result;
var transaction = db.transaction(['table1'], 'readwrite');
var objectStore = transaction.objectStore('table1');
var index = objectStore.index('name');
// 第一种,get方法
index.get('a').onsuccess = function (event) {
console.log(event.target.result);
}
// 第二种,普通游标方法
index.openCursor().onsuccess = function (event) {
console.log('openCursor:', event.target.result.value);
}
// 第三种,键游标方法,该方法与第二种的差别为:普通游标带有value值表示获取的数据,而键游标没有
index.openKeyCursor().onsuccess = function (event) {
console.log('openKeyCursor:', event.target.result);
}
}
当需要修改存储空间中的数据时,我们可以使用以下的API:
var objectStore = transaction.objectStore("customers");
var request = objectStore.put(data);
request.onsuccess = function (event) {
}
注:put
方法不仅能够修改现有数据,也能够往存储空间中增加新的数据。
当我们需要删除已经无用的数据时,我们可以通过以下方法:
var objectStore = transaction.objectStore("customers");
var request = objectStore.delete(name);
request.onsuccess = function (event) {
}
在浏览器有如下操作的情况下,indexedDB可能会出现异常:
此时,需要对错误进行捕获,并且对用户进行提示。此章节不是本文重点,再此略过。
在IndexedDB
中,键值对中的key
值可以接受以下几种类型的值:
具体说明可以见文档此处。
当一个key
值变为主键,即keyPath
时,它的值就只能是以下几种:
注:空格不能出现在key path中。
具体说明可以见文档此处。
在IndexedDB
中,value能够接受ECMA-262中所有的类型的值,例如String,Date,ImageDate等。
IndexedDB
在没有指定key值的时候就会采用自增的key值。如果一个事务在中途中断,那么key值的自增将会从中断的事务开始前的key开始。
IndexedDB
也受到浏览器同源策略的限制。
用户在清除浏览器缓存时,可能会清除IndexedDB
中相关的数据。
部分浏览器如Safari手机版隐私模式在访问IndexedDB
时,可能会出现由于没有权限而导致的异常(LocalStorage也会),需要进行异常处理。
IndexedDB
在本地存储中有着无可替代的作用,是替代关系型数据库web sql
的产品,能够对大量数据进行存储。在许多需要运用离线存储的场景下,它能够给我们提供有效的支撑。
但是,IndexedDB
在使用过程中仍然需要避免可能会出现的一些问题,或者对可能导致的不利影响有一定的容错处理。这样才不会对应用产生重大影响。
本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://github.com/HJava/myBlog
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。