概述
本文经由过程对IndexedDB
的应用要领和应用场景举行相干引见,对罕见的题目举行解答。
同时,因为MDN中的相干文档缺少相干逻辑性,所以不容易明白。本文将经由过程项目中罕见的数据存储和操纵需求来举行内容构造。
读者能够经由过程本文学会在项目中准确的应用IndexedDB
,给应用带来的当地存储才能,而且防止一些罕见的题目。
缘由:开辟者须要在当地举行永远存储
当我们举行一些较大的SPA页面开辟时,我们会须要举行一些数据的当地存储。
当数据量不大时,我们能够经由过程SessionStorage或许LocalStorage来举行存储,然则当数据量较大,或相符肯定的范例时,我们能够应用数据库来举行数据的存储。
在浏览器供应的数据库中,共有web sql
和IndexedDB
两种。相较于HTML5已烧毁的web sql
来讲,更引荐人人应用IndexedDB
。
构造
下面,我们经由过程一张图来相识下,IndexedDB团体的构造。
类比sql
型数据库,IndexedDB
中的DB(数据库)就是sql
中的DB,而Object Store(存储空间)
则是数据表
,Item
则即是表中的一条纪录
。
应用IndexedDB
如今,我们将其依据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
能够给当前的存储空间设置一个索引。它接收三个参数:
- 第一个参数,索引的称号。
- 第二个参数,指定依据存储数据的哪个属性来构建索引。
- 第三个属性, options对象,个中属性
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能够会涌现非常:
- 用户消灭浏览器缓存
- 存储空间凌驾大小限定
此时,须要对毛病举行捕捉,而且对用户举行提醒。此章节不是本文重点,再此略过。
扩大须知
取值相干
key值能够接收的数据范例
在IndexedDB
中,键值对中的key
值能够接收以下几种范例的值:
- number
- data
- string
- binary
- array
详细申明能够见文档此处。
key path能够接收的数据范例
当一个key
值变成主键,即keyPath
时,它的值就只能是以下几种:
- Blob
- File
- Array
- String
注:空格不能出如今key path中。
详细申明能够见文档此处。
value能够接收的数据范例
在IndexedDB
中,value能够接收ECMA-262中一切的范例的值,比方String,Date,ImageDate等。
事件相干
事件中缀后,会不会影响key值的自增
IndexedDB
在没有指定key值的时刻就会采纳自增的key值。假如一个事件在半途中缀,那末key值的自增将会从中缀的事件最先前的key最先。
平安相干
IndexedDB
也遭到浏览器同源战略的限定。
用户相干
清空缓存
用户在消灭浏览器缓存时,能够会消灭IndexedDB
中相干的数据。
接见权限
部份浏览器如Safari手机版隐私形式在接见IndexedDB
时,能够会涌现因为没有权限而致使的非常(LocalStorage也会),须要举行非常处置惩罚。
总结
IndexedDB
在当地存储中有着无可替换的作用,是替换关联型数据库web sql
的产物,能够对大批数据举行存储。在很多须要应用离线存储的场景下,它能够给我们供应有用的支持。
然则,IndexedDB
在应用过程中依然须要防止能够会涌现的一些题目,或许对能够致使的不利影响有肯定的容错处置惩罚。如许才不会对应用发生严重影响。