About IndexDB(转)
IndexedDB是用于客户端的大量的结构化数据存储和使用索引高效率搜索数据的API,它是基于W3C拟定的草案索引数据库的API。相对DOM存储的小存储数据量,IndexedDB具有大容量的数据存储功能,它分别为同步数据和异步数据提供的API,但目前只有异步数据的API在Gecko2.0 上实现。
一、 概述
1. IndexedDB存储为键值对:它可以存储一些复杂的对象,而键可以存储这些对像的属性值,并且可以使用索引对对象的属性的快速检索。
2. IndexedDB建立在交互数据库模型的基础上:任何对IndexedDB的操作都发生一个交互操作(transaction),如它提供的索引、表、游标等均与一个transaction关联,它定义了交互的生存时间与结束时抛出的事件,这样能很好的处理web程序在不同的tab窗口中实例的互操作。
3. IndexedDB的API大多是异步的:你可以向数据库发出操作的“请求”,当操作完成时会产生一个DOM事件,通过事件的类型会知道操作是否成功。
4. IndexedDB使用“请求”机制:操作对象会接收到DOM的success和failure事件,它也有相应的onsuccess和onerror的属性;对象还有readyState、result和errorCode属性来查看当前“请求”的状态,而result属性则根据不同的“请求”返回不同的结果。
5. IndexedDB 使用DOM事件机制来处理“请求”的结果:DOM事件的type属性提示操作是否成功,target属性指向发生“请求”的对象(大多数情况下是IDBRequest对象)。
6. IndexedDB工作基本模式:
0 创建一个交互操作对象
1 发送操作“请求”
2 通过监听DOM事件等待操作完成
3 处理“请求”结果
二、 打开数据库
IndexedDB的操作对象是以moz开头,如我们打开一个数据库如下:
1
|
var request = mozIndexedDB.open( "MyTestDatabase" );
|
mozIndexedDB对象只有一个open方法,它的参数即为数据库的名称,它返回一个IDBRequest对象。接下来要做的就是为request添加onsuccess和onerror事件的处理,它们分别在返回的DOM事件的type为success和error时调用,
01
|
request.onerror = function (event) {
|
02
|
03
|
// Do something with request.errorCode!
|
04
|
05
|
};
|
06
|
07
|
request.onsuccess = function (event) {
|
08
|
09
|
// Do something with request.result!
|
10
|
11
|
};
|
IndexedDB采用最小化的错误事件处理,你不会看到很多类型的错误,它只提供一个错误的事件,可以通过event.target.errorCode来查看错误的信息,通常大多的错误都是用户不允许web操作本地的数据库,远程web所拥有的权限问题。
三、 设置数据库的version
当创建数据库之后,需要添加数据,IndexedDB采用对象存储。首先要检查数据库的版本,若不是所期望的值,就要调用setVerion()方法来设置它的版本,如:
01
|
if (db.version != "1.0" ) {
|
02
|
03
|
var request = db.setVersion( "1.0" );
|
04
|
05
|
request.onerror = function (event) {
|
06
|
07
|
// Handle errors.
|
08
|
09
|
};
|
10
|
11
|
request.onsuccess = function (event) {
|
12
|
13
|
// Set up the database structure here!
|
14
|
15
|
};
|
16
|
17
|
}
|
IndexedDB存储的每一个对象均与一个key 关联,关于key 的获取方法参见()。同时我们还可以为对你的存储创建一个Index来查看存储对象部分属性值,如存储人的信息的数据库,我们希望保证不同的人拥有不同的email,就可以使用index和unique flag来设置,如:
01
|
// This is what our customer data looks like.
|
02
|
03
|
const customerData = [
|
04
|
05
|
{ ssn: "444-44-4444" , name: "Bill" , age: 35, email: "bill@company.com" },
|
06
|
07
|
{ ssn: "555-55-5555" , name: "Donna" , age: 32, email: "donna@home.org" }
|
08
|
09
|
];
|
10
|
11
|
var request = db.setVersion( "1.0" );
|
12
|
13
|
request.onerror = function (event) {
|
14
|
15
|
// Handle errors.
|
16
|
17
|
};
|
18
|
19
|
request.onsuccess = function (event) {
|
20
|
21
|
// Create an objectStore to hold information about our customers. We're
|
22
|
23
|
// going to use "ssn" as our key path because it's guaranteed to be
|
24
|
25
|
// unique.
|
26
|
27
|
var objectStore = db.createObjectStore( "customers" , { keyPath: "ssn" });
|
28
|
29
|
// Create an index to search customers by name. We may have duplicates
|
30
|
31
|
// so we can't use a unique index.
|
32
|
33
|
objectStore.createIndex( "name" , "name" , { unique: false });
|
34
|
35
|
// Create an index to search customers by email. We want to ensure that
|
36
|
37
|
// no two customers have the same email, so use a unique index.
|
38
|
39
|
objectStore.createIndex( "email" , "email" , { unique: true });
|
40
|
41
|
// Store values in the newly created objectStore.
|
42
|
43
|
for (i in customerData) {
|
44
|
45
|
objectStore.add(customerData[i]);
|
46
|
47
|
}
|
48
|
49
|
};
|
creatObjectStore()方法和createIndex()方法都有一个可选的对象选项来区分是创建数据库还是索引。creatObjectStore()方法会请求“customers”创建存储对象,并以ssn属性为存储对象的键值,任何试图存储进数据库的对象都需要有ssn属性;我们也可以通name的这个Index来查看存储对象,但对于没有name属性的对象将不会显示出来。
向数据库中添加数据
四、 在添加数据之前,需要先创建一个transaction,创建的方法有三个参数,后两个为可选的,第一个为要关联的数据库名称数组,第二个为打开此数据库的方式(如只读),若无则打开的方式为只读,如:
var transaction = db.transaction(["customers"],IDBTransaction.READ_WRITE);
一个transaction生存时间是与DOM 事件相关联的,如果创建它之后并在返回的事件中没有使用它,就会消亡,唯一让它处理激活状态的就去是使用“请求”机制,当一个请求完成后,在它的回调函数中继续请求,否则transaction就是会消亡。一个transaction有三个事件,为onerror、onsuccess和onabort,一个简单的例子:
01
|
// Do something when all the data is added to the database.
|
02
|
03
|
transaction.oncomplete = function (event) {
|
04
|
05
|
alert( "All done!" );
|
06
|
07
|
};
|
08
|
09
|
transaction.onerror = function (event) {
|
10
|
11
|
// Don't forget to handle errors!
|
12
|
13
|
};
|
14
|
15
|
var objectStore = transaction.objectStore( "customers" );
|
16
|
17
|
for ( var i in customerData) {
|
18
|
19
|
var request = objectStore.add(customerData[i]);
|
20
|
21
|
request.onsuccess = function (event) {
|
22
|
23
|
// event.target.result == customerData[i].ssn
|
24
|
25
|
};
|
26
|
27
|
}
|
五、 从数据库中删除数据
删除数据很简单,如下:
01
|
var request = db.transaction([ "customers" ], IDBTransaction.READ_WRITE)
|
02
|
03
|
.objectStore( "customers" )
|
04
|
05
|
. delete ( "444-44-4444" );
|
06
|
07
|
request.onsuccess = function (event) {
|
08
|
09
|
// It's gone!
|
10
|
11
|
};
|
六、 数据库中取数据
使用get()方法,参数为存储对象的key,如:
1
|
db.transaction( "customers" ).objectStore( "customers" ).get( "444-44-4444" ).onsuccess = function (event) {
|
2
|
3
|
alert( "Name for SSN 444-44-4444 is " + event.target.result.name);
|
4
|
5
|
};
|
七、 使用游标
使用get()方法需要知道存储对象的key值,但若不知道key值,要看存储对象,就可以使用游标,如下:
01
|
var objectStore = db.transaction( "customers" ).objectStore( "customers" );
|
02
|
03
|
objectStore.openCursor().onsuccess = function (event) {
|
04
|
05
|
var cursor = event.target.result;
|
06
|
07
|
if (cursor) {
|
08
|
09
|
alert( "Name for SSN " + cursor.key + " is " + cursor.value.name);
|
10
|
11
|
cursor. continue ();
|
12
|
13
|
}
|
14
|
15
|
else {
|
16
|
17
|
alert( "No more entries!" );
|
18
|
19
|
}
|
20
|
21
|
};
|
openCursor()方法有许多参数,首先你可设置遍历的Key的范围,其次可以设置游标遍历的方向。Continue();表示继续遍历。
八、 使用索引
在数据库中,所有的数据都是以SSN以key值来存储的,若要通过name等其他属性查看存储对象,需要遍历每个SSN并将它的name提取出判断是否为要查看的对象,但可以通过index而更为简单的实现,如:
1
|
var index = objectStore.index( "name" );
|
2
|
3
|
index.get( "Donna" ).onsuccess = function (event) {
|
4
|
5
|
alert( "Donna's SSN is " + event.target.result.ssn);
|
6
|
7
|
};
|
我们还可以通过index使用cursor来遍历存储的数据,并根据不同的cursor打开方式,返回不同的遍历结果,如下两种方式:
01
|
index.openCursor().onsuccess = function (event) {
|
02
|
03
|
var cursor = event.target.result;
|
04
|
05
|
if (cursor) {
|
06
|
07
|
// cursor.key is a name, like "Bill", and cursor.value is the whole object.
|
08
|
09
|
alert( "Name: " + cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);
|
10
|
11
|
cursor. continue ();
|
12
|
13
|
}
|
14
|
15
|
};
|
16
|
17
|
index.openKeyCursor().onsuccess = function (event) {
|
18
|
19
|
var cursor = event.target.result;
|
20
|
21
|
if (cursor) {
|
22
|
23
|
// cursor.key is a name, like "Bill", and cursor.value is the SSN.
|
24
|
25
|
// No way to directly get the rest of the stored object.
|
26
|
27
|
alert( "Name: " + cursor.key + ", " SSN: " + cursor.value);
|
28
|
29
|
cursor. continue ();
|
30
|
31
|
}
|
32
|
33
|
};
|
九、 关于游标遍历的范围和方向
如果想要限制游标的遍历范围,可以使用“key range”的对象,并将它做为openCursor()和openKeyCursor()的第一个参数,这样的范围可以是单个键值、或是一个最低边界和最高边界的范围,并规定是否包括范围,如下:
01
|
// Only match "Donna"
|
02
|
03
|
var singleKeyRange = IDBKeyRange.only( "Donna" );
|
04
|
05
|
// Match anything past "Bill", including "Bill"
|
06
|
07
|
var lowerBoundKeyRange = IDBKeyRange.lowerBound( "Bill" );
|
08
|
09
|
// Match anything past "Bill", but don't include "Bill"
|
10
|
11
|
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound( "Bill" , true );
|
12
|
13
|
// Match anything up to, but not including, "Donna"
|
14
|
15
|
var upperBoundOpenKeyRange = IDBKeyRange.upperBound( "Donna" , true );
|
16
|
17
|
//Match anything between "Bill" and "Donna", but not including "Donna"
|
18
|
19
|
var boundKeyRange = IDBKeyRange.bound( "Bill" , "Donna" , false , true );
|
20
|
21
|
index.openCursor(boundKeyRange).onsuccess = function (event) {
|
22
|
23
|
var cursor = event.target.result;
|
24
|
25
|
if (cursor) {
|
26
|
27
|
// Do something with the matches.
|
28
|
29
|
cursor. continue ();
|
30
|
31
|
}
|
32
|
33
|
};
|
另外,还可以规定游标遍历的方向,默认的是上升的方向,若使用相反的方向,可以将PREV作为openCursor()或是openKeyCursor()的第二个参数,如下:
01
|
objectStore.openCursor( null , IDBCursor.PREV).onsuccess = function (event) {
|
02
|
03
|
var cursor = event.target.result;
|
04
|
05
|
if (cursor) {
|
06
|
07
|
// Do something with the entries.
|
08
|
09
|
cursor. continue ();
|
10
|
11
|
}
|
12
|
13
|
};
|
需要注意的是,在索引中使用游标时,由于可能有多个键值是相同的,这时候总是返回最低边界的那一个对象,为解决此问题,将NEXT_NO_DUPLICATE 或是PREV_NO_DUPLICATE做为它的第二个参数,如下:
1
|
index.openKeyCursor( null , IDBCursor.NEXT_NO_DUPLICATE).onsuccess = function (event) {
|
2
|
var cursor = event.target.result;
|
3
|
if (cursor) {
|
4
|
// Do something with the entries.
|
5
|
cursor. continue ();
|
6
|
}
|
7
|
};
|
十、 数据库版本的变化
当web app需要请求数据库的变化时,要考虑用户在一个tab中打开老版本的app,而在另一个tab窗口中打开新版本的app时会发生什么情况,当你调用setVersion()时,所有其它打的数据库必须显示的接受该请求时,你才能对数据库进行更改。
01
|
mozIndexedDB.open( "MyTestDatabase" ).onsuccess = function (event) {
|
02
|
03
|
var db = event.target.result;
|
04
|
05
|
// If the database is at the correct version then we can skip straight to using it.
|
06
|
07
|
if (db.version == "1.0" ) {
|
08
|
09
|
useDatabase(db);
|
10
|
11
|
return ;
|
12
|
13
|
}
|
14
|
15
|
// Check that the database isn't a newer version already.
|
16
|
17
|
if (db.version != "" ) {
|
18
|
19
|
alert( "Database has a version which we don't know how to upgrade!" );
|
20
|
21
|
return ;
|
22
|
23
|
}
|
24
|
25
|
// Otherwise we need to change the version.
|
26
|
27
|
var request = db.setVersion( "1.0" );
|
28
|
29
|
request.onblocked = function (event) {
|
30
|
31
|
// If some other tab is loaded with the database, then it needs to be closed
|
32
|
33
|
// before we can proceed.
|
34
|
35
|
alert( "Please close all other tabs with this site open!" );
|
36
|
37
|
};
|
38
|
39
|
request.onsuccess = function (event) {
|
40
|
41
|
// All other databases have been closed. Set everything up.
|
42
|
43
|
db.createObjectStore( /* ... */ );
|
44
|
45
|
useDatabase(db);
|
46
|
47
|
};
|
48
|
49
|
};
|
50
|
51
|
function useDatabase(db) {
|
52
|
53
|
// Make sure to add a handler to be notified if another page requests a version
|
54
|
55
|
// change. We must close the database. This allows the other page to upgrade the database.
|
56
|
57
|
// If you don't do this then the upgrade won't happen until the user close the tab.
|
58
|
59
|
db.onversionchange = function (event) {
|
60
|
61
|
db.close();
|
62
|
63
|
alert( "A new version of this page is ready. Please reload!" );
|
64
|
65
|
};
|
66
|
67
|
// Do stuff with the database.
|
68
|
69
|
}
|
十一、 使用javascript Generators
注意:这只能在firefox中使用,不支持IE、chrome、Safari
Generators 在firefox中用于简化异步代码,但只能在javascript 1.7及后续的版本上,如:
<script type="text/javascript;version=1.7" src="myScript.js"></script>
myScript.js的内容如下:
01
|
// Need to stash the generator in a global variable.
|
02
|
03
|
var generator;
|
04
|
05
|
// Simple event listener function to pass the received event to the generator.
|
06
|
07
|
function grabEvent(event) {
|
08
|
09
|
generator.send(event);
|
10
|
11
|
}
|
12
|
13
|
// When we're all done we can close the generator, but that must happen outside
|
14
|
15
|
// of the generator so we use a timeout.
|
16
|
17
|
function closeGenerator() {
|
18
|
19
|
setTimeout( function () {
|
20
|
21
|
generator.close();
|
22
|
23
|
}, 0);
|
24
|
25
|
}
|
26
|
27
|
// Our main steps
|
28
|
29
|
function databaseOperation() {
|
30
|
31
|
mozIndexedDB.open( "MyTestDatabase" ).onsuccess = grabEvent;
|
32
|
33
|
var event = yield;
|
34
|
35
|
var db = event.target.result;
|
36
|
37
|
if (db.version != "1.0" ) {
|
38
|
39
|
db.setVersion( "1.0" ).onsuccess = grabEvent;
|
40
|
41
|
event = yield;
|
42
|
43
|
var transaction = event.transaction;
|
44
|
45
|
db.createObjectStore( "stuff" );
|
46
|
47
|
transaction.oncomplete = grabEvent;
|
48
|
49
|
yield;
|
50
|
51
|
}
|
52
|
53
|
db.transaction([ "stuff" ]).objectStore( "stuff" ).get( "foo" ).onsuccess = grabEvent;
|
54
|
55
|
event = yield;
|
56
|
57
|
alert( "Got result: " + event.target.result);
|
58
|
59
|
// We're all done.
|
60
|
61
|
closeGenerator();
|
62
|
63
|
// Always have an extra yield at the end or you will see StopIteration
|
64
|
65
|
// exceptions.
|
66
|
67
|
yield;
|
68
|
69
|
}
|
70
|
71
|
generator = databaseOperation();
|
72
|
73
|
generator.next();
|
十二、 安全性
需要注意的是IndexedDB在以iframe等方式加载到其它网站/网页是是不可运用的。
IDBRequest
它反应了向数据库IDBDatabase发出的请求的状况
属性:onsuccess --- 类型为函数,请求成功后执行,参数为请求成功产生的event(IDBSuccessEvent, IDBTransactionEvent)
Onerror --- 类型为函数,请求出错时执行,参数为错误时的event(IDBErrorEvent)
readyState --- 请求的状态,“1”为正在执行,“2”为执行完成
示例:
1
|
<pre>
|
2
|
3
|
var request = mozIndexedDB.open( "MyTestDatabase" ) ;
|
4
|
5
|
request.onerror = function (event) { //handle error };
|
6
|
7
|
request.onsuccess= function (event) { var db = request.result; //得到数据库对象,或db=event.target.result; };
|
8
|
9
|
</pre>
|
IDBSuccessEvent向IndexedDB请求成功后产生的DOM事件属性:使用event.target.result来得到请求成功后返回的结果,参见IDBRequest中示例!
转载于:https://www.cnblogs.com/tingzi/archive/2012/08/07/2626663.html
About IndexDB(转)相关推荐
- 使用HTML5 IndexDB存储图像和文件
使用IndexedDB存储图像和文件 有一天,我们写了关于如何在localStorage中保存图像和文件的文章,它是关于我们今天可用的实用主义. 然而,localStorage有一些性能影响 - 我们 ...
- 「工具」IndexDB 版备忘录
前言 工作日常需要做一些备忘录,记录一些要做的事.在 Mac 上有使用系统的备忘录,但功能偏弱且文本格式调整不方便.再就是使用浏览器找专门的备忘录网站,功能是满足了,但是链路长,没有桌面软件直接. 所 ...
- 前端 IndexDB 操作入门教程
前端 IndexDB 操作入门教程 idb-js 基于indexdb本地数据库的封装 文档地址 安装: npm install idb-js --save 使用: 第一步: 引入Idb import ...
- 前端存储之cookie、localStorage、sessionStorage、indexDB
cookie Cookie 是小甜饼的意思.顾名思义,cookie 确实非常小,它的大小限制为4KB左右,是网景公司的前雇员 Lou Montulli 在1993年3月的发明.它的主要用途有保存登录信 ...
- 各种本地存储对比 cookie,localStorage,sessionStorage,indexDB以及他们和vuex的区别
cookie 存储在cookie中的数据,每次都会被浏览器自动放在http请求中,如果这些数据并不是每个请求都需要发给服务端的数据,浏览器这设置自动处理无疑增加了网络开销:但如果这些数据是每个请求都需 ...
- 本地存储Cookie、Storage、indexDB、ServiceWork离线访问网站
在日常开发中,开发者用得最多的大概是前三种吧,cookie.Session/Local,对后两种运用的较少,话不多少,直接正文: cookie cookie是客户端的解决方案,最早是网景公司的前雇员L ...
- VUE + idb-js 应用 indexDB
装包 npm i idb-js 2023-6-13 , 优化一波使用 重新封装 table.js 在实际使用中, 发现, idb-js 不支持动态增加 表, 因此当存在多个项目使用同一套 代码时, 会 ...
- Cesium 使用 indexdb
CesiumOfflineCache 这是一个 Cesium 插件,它使用 indexDB 离线缓存技术管理 影像图层.地形.3DTiles模型 等资源数据. https://github.com/W ...
- html5 indexdb api,html5 indexDB实例
IndexedDB是用于客户端的大量的结构化数据存储和使用索引高效率搜索数据的API,它是基于W3C拟定的草案索引数据库的API.相对DOM存储的小存储数据量,IndexedDB具有大容量的数据存储功 ...
- php indexdb,前端存储 (4) - IndexDB
IndexDB的出现 是为了存储更大量的结构化数据 简介 IndexedDB是一个事务型数据库系统,类似于基于SQL的RDBMS. 然而不同的是它使用固定列表(只有 key,value),Indexe ...
最新文章
- 【luogu 3375】【模板】KMP字符串匹配
- easyUI的引用顺序
- BAT批处理脚本结合SQL应用案例
- 【除夕最炫烟花代码】—— HTML+JQuery实现2022跨年烟花特效
- 属于服务器端运行的程序_生信分析云平台产品开发 - 5 生信分析pipeline服务器端运行...
- c++ abort 函数_C ++中带有示例的abort()函数
- C机顶盒开发实战常量定义方式、结构定义方式(可理解为对象Model)
- IC芯片卡读写类(泛型模式)
- 产品经理和项目经理的职责分工
- 【南宋】【文天祥】正气歌
- 查看欧拉系统服务器ip,EulerOS 系统配置
- 用脑电波控制智能假肢:如何利用深度学习技术进行EGG数据分类
- 第三章 灰度变换与空间滤波
- php curl发邮件,使用PHP cURL通过Mailgun API发送带附件的电子邮件
- 电脑如何同时安装JDK11和JDK1.8(适用于多个JDK)
- Apache Druid历险记
- 上楼梯的走法 ← 递归
- 小程序嵌套h5页面_微信小程序内嵌h5页面
- Kewail:三种常用的邮件内容传送编码
- 数据结构和算法之暴力递归到动态规划01-绝顶聪明纸牌问题
热门文章
- mysql从表截取信息_mysql中循环截取用户信息并插入到目标表对应的字段中
- mysql主从配置错误_mysql主从配置失败,主从通讯失败
- python 修改array_python 基础_ 数组的 增删改查3
- redhat linux7.0的安装
- 做自适应网站专业乐云seo_自适应网站方案品牌乐云seo
- 【设计模式之美】<Reading Notes>继承与组合
- Opencv实战【1】人脸检测并对ROI区域进行部分处理(变身乔碧萝!!!)
- 实验8 SQL Server 的存储过程
- Java——集合转数组并对其进行遍历
- Java——File类