indexedDB
indexedDB 是 window 上的一个只读属性,返回 IDBFactory 对象,IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。
此特性在 Web Worker 中可用。正如大多数的 web 储存解决方案一样,IndexedDB 也遵守同源策略。因此当你在某个域名下操作储存数据的时候,你不能操作其他域名下的数据。
IndexedDB 是一个事务型数据库系统,基于 JavaScript 的面向对象数据库。允许你存储和检索用键索引的对象;可以存储结构化克隆算法支持的任何对象。你只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务。
ndexedDB 鼓励使用的基本模式如下所示:
- 打开数据库。
- 在数据库中创建一个对象存储(object store)。
- 启动事务,并发送一个请求来执行一些数据库操作,如添加或获取数据等。
- 通过监听正确类型的 DOM 事件以等待操作完成。
- 对结果进行一些操作(可以在 request 对象中找到)
js
let customerData = [
{ name: "zhangjinxi", age: 18, email: "1334640772@qq.com", ssn: 121121323 },
{ name: "张三", age: 20, email: "23223423423@qq.com", ssn: 23232323 },
];
// 打开或者创建成功时,添加onversionchange事件处理器。
function useDatabase(db) {
// 其他标签页请求版本变更时会触发onversionchange事件。
// 这里必须关闭数据库,允许其他标签页更新数据库。
// 如果不这样做,在用户关闭这些标签页之前,版本升级将不会发生。
db.onversionchange = event => {
db.close();
console.log("此页面的新版本已准备就绪。请重新加载或关闭此标签页!");
};
//数据库关闭事件
db.onclose=(event)=>{
console.log('数据库关闭了')
}
}
// 打开或者创建名字为dbName,版本为2的数据库
const request = indexedDB.open("dbName", 2);
// 删除database
// const request = indexedDB.deleteDatabase(name, options)
// 数据库打开失败处理函数
request.onerror = event => {
// 错误处理
};
// 数据库打开成功处理函数
request.onsuccess = event => {
const db = event.target.result;
useDatabase(db);
return;
};
//
request.onblocked = event => {
// 当使用更高的版本号调用 open() 方法时,其他所有标签页打开的数据库必须显式地确认请求,才能对数据库进行修改(onblocked 事件会被触发,直到它们被关闭或重新加载)。
console.log("请关闭其他打开了该站点的标签页!");
};
// 新创建或者版本号改变时,触发onupgradeneeded事件
request.onupgradeneeded = event => {
// 获取IDBDatabase对象:数据库对象
const db = event.target.result;
useDatabase(db);
// 创建一个名为customers的对象存储,将对象中不会重复的key:email作为键路径
const objectStore = db.createObjectStore("customers", { keyPath: "email" });
// 创建另一个名为“names”的对象存储,并将 autoIncrement 标志设置为真。
const objStore = db.createObjectStore("names", { autoIncrement: true });
/**
* @indexName 索引名
* @keyPath 索引名使用的keyPath
* @options
* unique 是否允许存在重复的值,默认false
* multiEntry 如果为true,则当keyPath解析为数组时,索引将在索引中为每个数组元素添加一个条目。如果为false,它将添加一个包含该数组的单条目。默认为false。
* @return IDBIndex对象
*/
objectStore.createIndex("name", "name", { unique: false });
// 使用邮箱建立索引,我们想确保客户的邮箱不会重复,所以我们使用 unique 索引。
objectStore.createIndex("email", "email", { unique: true });
// 使用索引查找数据,返回查找到的第一条数据
const index = objectStore.index("name");
index.get("zhangjinxi").onsuccess = event => {
console.log(`${event.target.result}`);
};
// 使用事务的 oncomplete 事件确保在插入数据前对象存储已经创建完毕。
objectStore.transaction.oncomplete = event => {
// 通过事务拿到名为customers的对象储存:customerObjectStore
/**
* @customers 作用域,一个你想访问的对象存储的数组
* @readwrite 事务如何操作数据
* readonly 默认值
* readwrite
* versionchange:此类事务中才能修改数据库的“模式”或结构(包括新建或删除对象存储、索引)
*/
const transactionCustomers = db.transaction(["customers"], "readwrite");
// 在所有数据添加完毕后的处理
transactionCustomers.oncomplete = event => {
console.log("全部完成了!");
};
transactionCustomers.onerror = event => {
// 不要忘记错误处理!error 事件是冒泡机制,所以事务会接收由它产生的所有请求所产生的错误
};
transactionCustomers.abort = event => {
// 事务中没有处理一个已发生的错误事件或者调用了 abort() 方法,那么该事务会被回滚,并触发 abort 事件
};
const customerObjectStore = transactionCustomers.objectStore("customers");
// 添加数据:通过遍历将数据保存到新创建的对象存储中。
customerData.forEach(customer => {
const request = customerObjectStore.add(customer);
request.onsuccss = event => {
// event.target.result === customer.email 返回keyPath
};
});
// 删除数据:通过指定的keyPath
const deleteRequest = customerObjectStore.delete("23223423423@qq.com");
deleteRequest.onsuccess = event => {
const deleteItem = event.target.result;
console.log("删除成功,删除的item为:", deleteItem);
};
// 查询数据:通过指定的keyPath。还有getAll() 和 getAllKeys()
const getRequest = customerObjectStore.get("23223423423@qq.com");
getRequest.onsuccess = event => {
// 也等于:getRequest.result
const getItem = event.target.result;
console.log("查询的item为:", getItem);
};
let putObj = {
name: "张三",
age: 200,
email: "23223423423@qq.com",
ssn: 23232323,
};
// 更新数据:通过指定的keyPath,更新对应keyPath的数据
const putRequest = customerObjectStore.put(putObj);
putRequest.onsuccess = event => {
console.log("数据已经成功更新");
};
putRequest.onerror = event => {
console.log("数据更新失败");
};
};
};
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
游标
使用 get() 要求你知道你想要检索哪一个键。如果你想要遍历对象存储空间中的所有值,那么你可以使用游标。看起来会像下面这样:
js
const customers = [];
/**openCursor 或者openKeyCursor 的参数
* @keyRange key range 对象来限制被检索的项目的范围
* @order 进行迭代的方向,默认升序迭代。prev降序
* @return 请求的result
*/
objectStore.openCursor().onsuccess = event => {
// 到达数据的末尾时仍然会得到一个成功回调,但是 result 属性是undefined
const cursor = event.target.result;
if (cursor) {
// openCursor时value为整个对象。openKeyCursor时value为keyPath值
customers.push(cursor.value);
console.log(`email ${cursor.key} 对应的对象是 ${cursor.value}`);
// 想要继续,那么你必须调用游标上的 continue()
cursor.continue();
} else {
console.log(`已获取的所有客户:${customers}`);
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
指定游标的范围和方向
js
// 仅匹配“Donna”
const singleKeyRange = IDBKeyRange.only("Donna");
// 匹配所有大于“Bill”的,包括“Bill”
const lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");
// 匹配所有大于“Bill”的,但不包括“Bill”
const lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);
// 匹配所有小于“Donna”的,不包括“Donna”
const upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);
// 匹配所有在“Bill”和“Donna”之间的,但不包括“Donna”
const boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);
// 使用其中的一个键范围,把它作为 openCursor()/openKeyCursor() 的第一个参数
index.openCursor(boundKeyRange, "prev").onsuccess = event => {
const cursor = event.target.result;
if (cursor) {
// 对匹配结果进行一些操作。
cursor.continue();
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23