在知乎和我在日常工做中,经常会看到一个问题:前端
前端如今还火吗?git
这个我只想说:github
隔岸观火的人永远没法明白起火的缘由,只有置身风暴,才能找到风眼之所在 ——『秦时明月』web
你 TM 看都不看前端如今的发展,怎么去评判前端火不火,我该不应尝试一下其余方面的内容呢?本人为啥为这么热衷于新的技术呢?主要缘由在于,生怕会被某一项颠覆性的内容淘汰掉,从前沿领域掉队下来。说句人话就是:穷,因此只能学了...
。因此本文会从头剖析一下 IndexedDB
在前端里面的应用的发展。chrome
indexedDB 目前在前端慢慢获得普及和应用。它正朝着前端离线数据库技术的步伐前进。之前一开始是 manifest、localStorage、cookie 再到 webSQL,如今 indexedDB 逐渐被各大浏览器承认。咱们也能够针对它来进行技术上创新的开发。好比,如今小视频很是流行,那么咱们能够在用户观看时,经过 cacheStorage 缓存,而后利用 WebRTC 技术实现 P2P 分发的控制,不过须要注意,必定要合理利用大小,否则后果然的很严重。数据库
indexedDB 的总体架构,是由一系列单独的概念串联而成,所有概念以下列表。一眼看去会发现没有任何逻辑,不过,这里我顺手画了一幅逻辑图,中间会根据 函数 的调用而相互串联起来。api
总体逻辑图以下:数组
下文主要介绍了 indexedDB 的基本概念,以及在实际应用中的实操代码。promise
index
、cursor
等高效的索引机制,推荐不要直接将全部数据都取回来,再进行筛选,而是直接利用 cursor
进行。更多能够关注个人公众号:前端小吉米 (二维码在文章底部)浏览器
IndexedDB 能够存储很是多的数据,好比 Object,files,blobs 等,里面的存储结构是根据 Database 来进行存储的。每一个 DB 里面能够有不一样的 object stores。具体结构以下图:
而且,咱们能够给 key
设定相关特定的值,而后在索引的时候,能够直接经过 key 获得具体的内容。使用 IndexDB 须要注意,其遵循的是同域原则。
在 indexDB 中,有几个基本的操做对象:
open
方法直接打开,能够获得一个实例的 DB。每一个页面能够建立多个 DB,不过通常都是一个。idb.open(name, version, upgradeCallback)
复制代码
以下 code 为:
// 建立 index
var myIndex = objectStore.index('lName');
复制代码
var trans1 = db.transaction("foo", "readwrite");
var trans2 = db.transaction("foo", "readwrite");
var objectStore2 = trans2.objectStore("foo")
var objectStore1 = trans1.objectStore("foo")
objectStore2.put("2", "key");
objectStore1.put("1", "key");
复制代码
openCursor
来进行控制。function displayData() {
var transaction = db.transaction(['rushAlbumList'], "readonly");
var objectStore = transaction.objectStore('rushAlbumList');
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
var listItem = document.createElement('li');
listItem.innerHTML = cursor.value.albumTitle + ', ' + cursor.value.year;
list.appendChild(listItem);
cursor.continue();
} else {
console.log('Entries all displayed.');
}
};
}
复制代码
上面说了几个基本的概念。那接下来咱们实践一下 IndexDB。实际上入门 IndexDB 就是作几个基本的内容
前期搭建一个 IndexedDB 很简单的代码以下:
var request = indexedDB.open(dbName, 2);
request.onerror = function(event) {
// 错误处理程序在这里。
};
request.onupgradeneeded = function(event) {
var db = event.target.result;
// 设置 id 为 primaryKey 参数
var objectStore = db.createObjectStore("customers", { keyPath: "id",{autoIncrement:true} });
// 设置指定索引,并确保惟一性
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("email", "email", { unique: true });
};
复制代码
上面主要作了 3 件事:
打开数据库表主要就是版本号和名字,没有太多讲的,咱们直接从建立 store 开始吧。
使用的方法就是 IDBDatabase 上的 createObjectStore
方法。
var objectStore = db.createObjectStore("customers", { keyPath: "id",{autoIncrement:true} });
复制代码
基本函数构造为:
IDBObjectStore createObjectStore(DOMString name,
optional IDBObjectStoreParameters options)
dictionary IDBObjectStoreParameters {
(DOMString or sequence<DOMString>)? keyPath = null;
boolean autoIncrement = false;
};
复制代码
建立的 key 主要是为了保证,在数据插入时惟一性的标识。
不过,每每一个主键(key),是没办法很好的完成索引,在具体实践时,就还须要辅键 (aid-key) 来完成辅助索引工做,这个在 IndexDB 就映射为 index
。
在完成 PK(Primary key) 建立完毕后,为了更好的搜索性能咱们还须要额外建立 index
。这里能够直接使用:
objectStore.createIndex('indexName', 'property', options);
复制代码
其中,options 有三个选项:
# 建立一个名字叫 titleIndex 的 index,而且存储的 index 不能重复
DB.createIndex('titleIndex', 'title', {unique: false});
复制代码
具体能够参考:MDN createIndex Prop 和 googleDeveloper Index。
在 IndexedDB 里面进行数据的增删,都须要在 transaction
中完成。而这个增删数据,你们能够理解为一次 request
,至关于在一个 transaction
里面管理全部当前逻辑操做的 request
。因此,在正式开始进行数据操做以前,还须要给你们简单介绍一些若是建立一个事务。
transaction
API,以下 [代码1]。在建立时,你须要手动指定当前 transaction 是那种类型的操做,基本的内容有:
upgradeneeded
回调事件里面自动建立。它能够用来修改现有 object store 的结构数据,好比 index 等。你能够经过在数据库打开以后,经过 IDBDataBase
上的 transaction
方法建立,如 [代码2]。
[代码1]
[NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
optional IDBTransactionMode mode = "readonly");
[代码2]
var transaction = db.transaction(["customers"], "readwrite");
var objectStore = transaction.objectStore("customers");
# 遍历存储数据
for (var i in customerData) {
var request = objectStore.add(customerData[i]);
request.onsuccess = function(event) {
// success, done?
};
}
复制代码
事务在建立的时候不只仅能够制定执行的模式,还能够指定本次事务可以影响的 ObjectStore 范围,具体细节就是在第一个 transaction
参数里面传入的是一个数据,而后经过 objectStore()
方法打开多个 OS 进行操做,以下 [代码3]。
[代码3]
var tx = db.transaction(["books","person"], "readonly");
var books = tx.objectStore("books");
var person = tx.objectStore("person");
复制代码
完成了事务的建立以后,咱们就能够正式的开始进行数据的交互操做了,也就是写咱们具体的业务逻辑。以下 [代码1],一个完整数据事务的操做。
[代码1]
var tx = db.transaction("books", "readwrite");
var store = tx.objectStore("books");
store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
tx.oncomplete = function() {
// All requests have succeeded and the transaction has committed.
};
复制代码
经过 objectStore
回调获得的 IDBObjectStore 对象,咱们就能够进行一些列的增删查改操做了。能够参考 [代码2]。详细的能够参考文末的 appendix
。
[代码2]
[NewObject] IDBRequest put(any value, optional any key);
[NewObject] IDBRequest add(any value, optional any key);
[NewObject] IDBRequest delete(any query);
复制代码
索引数据是全部数据库里面最重要的一个。这里,咱们可使用游标,index 来作。例如,经过 index 来快速索引 key 值,参考 [代码1]。
[代码1]
var index = objectStore.index("name");
index.get("Donna").onsuccess = function(event) {
alert("Donna's SSN is " + event.target.result.ssn);
};
复制代码
更详细的内容,能够参考下文 数据索引方式。
何谓 keyPath 和 keyGenerator 应该算是 IndexedDB 里面比较难以理解的概念。简单来讲,IndexedDB 在建立 Store 的时候,必须保证里面的数据是惟一的,那么得须要像其它数据库同样设置一个 primary Key
来区分不一样数据。而 keyPath 和 Generator 就是两种不一样的设置 key 的方式。
设置 keyPath
# 设置预先须要存放的数据
const customerData = [
{ ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },
{ ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" }
];
# 经过 keyPath 设置 Primary Key
var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
复制代码
由于 ssn 在该数据集是惟一的,因此,咱们能够利用它来做为 keyPath
保证 unique
的特性。或者,能够设置为自增的键值,好比 id++
相似的。
upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement:true});
复制代码
使用 generator
generator 会每次在添加数据时,自动建立一个 unique value。这个 unique value 是和你的实际数据是分开的。里面直接经过 autoIncrement:true
来设置便可。
upgradeDb.createObjectStore('notes', {autoIncrement:true});
复制代码
检查是否支持 indexDB
if (!('indexedDB' in window)) {
console.log('This browser doesn\'t support IndexedDB'); return; } 复制代码
版本更新: indexDB
在生成一个 indexDB 实例时,须要手动指定一个版本号。而最经常使用的
idb.open('test-db7', 2, function(upgradeDb) {})
复制代码
这样会形成一个问题,好比上线过程当中,用户A第一次请求返回了新版本的网页,链接了版本2。以后又刷新网页命中了另外一台未上线的机器,链接了旧版本1 出错。主要缘由是:
indexedDB API 中不容许数据库中的数据仓库在同一版本中发生变化. 而且当前 DB 版本不能和低版本的 version 链接。
好比,你一开始定义的 DB 版本内容为:
# 版本必定义的内容
db.version(1).stores({friends: "++id,name"});
# 版本二修改结构为:
db.version(2).stores({friends: "++id,name,shoeSize"});
复制代码
若是此时,用户先打开了 version(1),可是后面,又获得的是 version(2) 版本的 HTML,这时就会出现 error 的错误。
参考:
这个在 IndexDB 是一个很重要的问题。主要缘由在于
indexedDB API 中不容许数据库中的数据仓库在同一版本中发生变化. 而且当前 DB 版本不能和低版本的 version 链接。
上面就能够抽象为一个问题:
你什么状况下须要更新 IndexDB 的版本呢?
keyPath
时。# 版本 1 的 DB 设计,有一个主键 id 和 index-name
db
.version(1)
.stores({friends: '++id,name'})
# 若是直接想新增一个 key,例如 male,是没法成功的
db
.version(1)
.stores({friends: '++id,name,male'})
# 正确办法是直接修改版本号更新
db
.version(2)
.stores({friends: '++id,name,male'})
复制代码
不过,若是直接修改版本号,会出现这样一个 case:
解决办法就是,设置过滤,在 open
的时候,手动传入版本号:
# 打开版本 1 的数据库
var dbPromise = idb.open('db1', 1, function(upgradeDb){...})
# 打开版本 2 的数据库
var dbPromise = idb.open('db2', 2, function(upgradeDb){...})
复制代码
不过,这样又会形成另一个问题,即,数据迁移(老版本数据,不可能不要吧)。这里,IndexDB 会有一个 updateCallback 给你触发,你能够直接在里面作相关的数据迁移处理。
var dbPromise = idb.open('test-db7', 2, function(upgradeDb) {
switch (upgradeDb.oldVersion) {
case 0:
upgradeDb.createObjectStore('store', {keyPath: 'name'});
case 1:
var peopleStore = upgradeDb.transaction.objectStore('store');
peopleStore.createIndex('price', 'price');
}
});
复制代码
在使用的时候,必定要注意 DB 版本的升级处理,好比有这样一个 case,你的版本已是 3,不过,你须要处理版本二的数据:
# 将版本二 中的 name 拆分为 firstName 和 lastName
db.version(3).stores({friends: "++id,shoeSize,firstName,lastName"}).upgrade(function(t) {
return t.friends.toCollection().modify(function(friend) {
// Modify each friend:
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
delete friend.name;
});
});
复制代码
对于存在版本 2 数据库的用户来讲是 OK 的,可是对于某些尚未访问过你数据库的用户来讲,这无疑就报错了。解决办法有:
在 Dexie.js DB 数据库中,须要你保留每次 DB 建立的方法,其实是经过 添加 swtich case ,来完成每一个版本的更新:
# Dexie.js 保留 DB 数据库
db.version(1).stores({friends: "++id,name"});
db.version(2).stores({friends: "++id,name,shoeSize"});
db.version(3).stores({friends: "++id,shoeSize,firstName,lastName"}).upgrade(...)
# 内部原理,直接添加 switch case 完成版本更新
var dbPromise = idb.open('test-db7', 2, function(upgradeDb) {
switch (upgradeDb.oldVersion) {
case 0:
upgradeDb.createObjectStore('store', {keyPath: 'name'});
case 1:
var peopleStore = upgradeDb.transaction.objectStore('store');
peopleStore.createIndex('price', 'price');
}
});
复制代码
若是遇到一个页面打开,可是另一个页面拉取到新的代码进行更新时,这个时候还须要将低版本 indexedDB 进行显式的关闭。具体操做办法就是监听 onversionchange
事件,当版本升级时,通知当前 DB 进行关闭,而后在新的页面进行更新操做。
openReq.onupgradeneeded = function(event) {
// 全部其它数据库都已经被关掉了,直接更新代码
db.createObjectStore(/* ... */);
db.onversionchange = function(event) {
db.close();
};
}
复制代码
最后,更新是还有几个注意事项:
有时候,咱们存储时,想获得一个由一串 String 生成的 hash key,那在 Web 上应该如何实现呢?
这里能够直接利用 Web 上已经实现的 WebCrypto,为了实现上述需求,咱们能够直接利用里面的 digest
方法便可。这里 MDN 上,已经有现成的办法,咱们直接使用便可。
参考:
基本限制为:
浏览器 | 限制 |
---|---|
Chrome | 可用空间 < 6% |
Firebox | 可用空间 < 10% |
Safari | < 50MB |
IE10 | < 250MB |
逐出策略为:
浏览器 | 逐出政策 |
---|---|
Chrome | 在 Chrome 耗尽空间后采用 LRU 策略 |
Firebox | 在整个磁盘已装满时采用 LRU 策略 |
Safari | 无逐出 |
Edge | 无逐出 |
参考:
在数据库中除了基本的 CRUD 外,一个高效的索引架构,则是里面的重中之重。在 indexedDB 中,咱们一共能够经过三种方式来索引数据:
IDBObjectStore 提供给了咱们直接经过 primaryKey
来索引数据,参考 [代码1],这种方式须要咱们一开始就知道目标的 key
内容。固然,也能够经过 getAll
所有索引数据。
[代码1]
[NewObject] IDBRequest get(any query);
[NewObject] IDBRequest getKey(any query);
[NewObject] IDBRequest getAll(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest getAllKeys(optional any query,
optional [EnforceRange] unsigned long count);
复制代码
好比,咱们经过 primaryKey 获得一条具体的数据:
db.transaction("customers").objectStore("customers").get("id_card_1118899").onsuccess = function(event) {
// data is event.target.result.name
};
复制代码
也能够 fetch 整个 Object Store 的数据。这些场景用处比较少,这里就不过多讲解。咱们主要来了解一下 index 的索引方式。
若是想要查询某个数据,直接经过整个对象来进行遍历的话,这样作性能耗时是很是大的。若是咱们结合 index
来将 key 加以分类,就能够很快速的实现指定数据的索引。这里,咱们能够直接利用 IDBObjectStore 上面的 index()
方法来获取指定 index 的值,具体方法能够参考 [代码1]。
[代码1]
IDBIndex index(DOMString name);
复制代码
该方法会直接返回一个 IDBIndex 对象。这你也能够理解为一个相似 ObjectStore 的微型 index 数据内容。接着,咱们可使用 get()
方法来得到指定 index 的数据,参考[代码2]。
[代码2]
var index = objectStore.index("name");
index.get("Donna").onsuccess = function(event) {
alert("Donna's SSN is " + event.target.result.ssn);
};
复制代码
使用 get
方法无论你的 index 是不是 unique
的都会只会返回第一个数据。若是想获得多个数据的话,可使用 getAll(key)
来作。经过 getAll()
获得的回调函数,直接经过 event.target.result
能够获得对应的 value 内容。
objectStore.getAll().onsuccess = function(event) {
printf(event.target.result); // Array
};
复制代码
除了经过 getAll()
获得全部数据外,还能够采用更高效的 cursor
方法遍历获得的数据。
参考:
所谓的游标,你们内心应该能够有一个初步的印象,就像咱们物理尺子上的那个东西,能够自由的移动,来标识指向的对象内容。cursor 里面有两个核心的方法:
好比,咱们使用 cursor 来遍历 Object Store 的具体数据。
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
// cursor.key
// cursor.value
cursor.continue();
} else {
console.log('Entries all displayed.');
}
};
复制代码
一般,游标能够用来遍历两个类型的数据,一个是 ObjectStore、一个是 Index。
primaryKey
遍历整个数据,注意,这里不会存在重复的状况,由于 primaryKey
是惟一的。在 IDBObjectStore 对象上有两种方法来打开游标:
这里,咱们经过 openCursor
来直接打开一个 index 数据集,而后进行遍历。
PersonIndex.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
customers.push(cursor.value);
cursor.continue();
}
else {
alert("Got all customers: " + customers);
}
};
复制代码
在游标中,还提供给了一个 update
和 delete
方法,咱们能够用它来进行数据的更新操做,不然的话就直接使用 ObjectStore 提供的 put
方法。
游标里面咱们还能够限定其遍历的范围和方向。这个设置是咱们直接在 openCursor()
方法里面传参完成的,该方法的构造函数参考 [代码1]。他里面能够传入两个参数,第一个用来指定范围,第二个用来指定 cursor
移动的方向。
[代码1]
IDBRequest openCursor(optional any query,
optional IDBCursorDirection direction = "next");
复制代码
若是须要对 cursor 设置范围的话,就须要使用到 IDBKeyRange
这个对象,使用样板能够参考 [代码2]。IDBKeyRange 里面 key 参考的对象 因使用者的不一样而不一样。若是是针对 ObjectStore 的话,则是针对 primaryKey,若是是针对 Index 的话,则是针对当前的 indexKey
/ 匹配全部在 “Bill” 前面的, 可是不须要包括 "Bill"
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);
复制代码
好比,咱们这里对 PersonIndex 设置一个 index 范围,即,索引 在 villainhr
和 jimmyVV
之间的数据集合。
# 都包括 villainhr 和 jimmyVV 的数据
var boundKeyRange = IDBKeyRange.bound("villainhr", "jimmyVV", true, true);
PersonIndex.openCursor(boundKeyRange).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
// Do something with the matches.
cursor.continue();
}
};
复制代码
若是你还想设置遍历的方向和是否排除重复数据,还能够根据 [代码2] 的枚举类型来设置。好比,在 [代码3] 中,咱们改变默认的 cursor 遍历数据的方向为 prev
,从末尾开始。
[代码2]
enum IDBCursorDirection {
"next",
"nextunique",
"prev",
"prevunique"
};
[代码3]
objectStore.openCursor(null, IDBCursor.prev).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
// cursor.value
cursor.continue();
}
};
复制代码
在 indexDB 里面的读写所有是基于 transaction
模式来的。也就是 IDBDataBase 里面的 transaction
方法,以下 [代码1]。全部的读写均可以比做在 transaction
做用域下的请求,只有当全部请求完成以后,该次 transaction
才会生效,不然就会抛出异常或者错误。transaction
会根据监听 error,abort,以及 complete 三个事件来完成整个事务的流程管理,参考[代码2]。
[代码1]
[NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
optional IDBTransactionMode mode = "readonly");
[代码2]
attribute EventHandler onabort;
attribute EventHandler oncomplete;
attribute EventHandler onerror;
复制代码
例如:
var request = db.transaction(["customers"], "readwrite")
.objectStore("customers")
.delete("gg");
request.onsuccess = function(event) {
// delete, done
};
复制代码
你能够在 transaction
方法里面手动传入 readwrite
或者其余表示事务的 readonly
参数,来表示本次事务你会进行如何的操做。IndexedDB 在初始设计时,就已经决定了它的性能问题。
只含有 readonly 模式的 transaction 能够并发进行执行 含有 write 模式的 transaction 必须按照队列 来 执行
这就意味着,若是你使用了 readwrite
模式的话,那么后续无论是否是 readonly
都必须等待该次 transaction 完成才行。
指定 primaryKey 生成时,是经过 createObjectStore
方法来操做的。有时候,咱们会遇到想直接获得一个 key,而且存在于当前数据集中,能够在 options 中同时加上 keyPath
和 autoIncrement
属性。该 key 的范围是 [1- ],参考 keygenerator key 的大小
db.createObjectStore('table1', {keyPath: 'id', autoIncrement: true});
复制代码
阅读推荐
indexedDB W3C 文档 indexedDB 入门 MDN indexedDB 入门
好用库推荐
在如下状况下,数据库可能被清除:
数据库
数据库: 一般包含一个或多个 object stores. 每一个数据库必须包含如下内容:
对象存储(object store): 用来承载数据的一个分区.数据以键值对形式被对象存储永久持有。在 OS 中,建立一个 key 可使用 key generator
和 key path
。
具体数据 key/value
id++
的形式来生成一个 key 值。操做做用域
参考:
这其实就是 indexDB
上面挂载的对象。主要 API 以下:
[Exposed=(Window,Worker)]
interface IDBFactory {
[NewObject] IDBOpenDBRequest open(DOMString name,
optional [EnforceRange] unsigned long long version);
[NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);
short cmp(any first, any second);
};
复制代码
你能够直接经过 open
来打开一个数据库。经过 返回一个 Request 对象,来进行结果监听的回调:
var request = indexedDB.open('AddressBook', 15);
request.onsuccess = function(evt) {...};
request.onerror = function(evt) {...};
复制代码
参考:
当你经过 open
方法处理事后,就会获得一个 Request 回调对象。这个就是 IDBRequest 的实例。
[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
readonly attribute any result; // 经过 open 打开事后的 IDBObjectStore 实例
readonly attribute DOMException? error;
readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
readonly attribute IDBTransaction? transaction;
readonly attribute IDBRequestReadyState readyState;
// Event handlers:
attribute EventHandler onsuccess;
attribute EventHandler onerror;
};
enum IDBRequestReadyState {
"pending",
"done"
};
[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
// Event handlers:
attribute EventHandler onblocked;
attribute EventHandler onupgradeneeded;
};
复制代码
你能够经过 result
获得当前数据库操做的结果。若是你打开更新后的版本号的话,还须要监听 onupgradeneeded
事件来实现。最常经过 indexedDB.open 碰见的错误就是 VER_ERR
版本错误。这代表存储在磁盘上的数据库的版本高于你试图打开的版本。
db.onerror = function(event) {
// Generic error handler for all errors targeted at this database's // requests! alert("Database error: " + event.target.errorCode); }; 复制代码
因此,通常在建立 IndexDB 时,还须要管理它版本的更新操做,这里就须要监听 onupgradeneeded 来是实现。
request.onupgradeneeded = function(event) {
// 更新对象存储空间和索引 ....
};
复制代码
或者咱们能够直接使用 idb
微型库来实现读取操做。
var dbPromise = idb.open('test-db3', 1, function(upgradeDb) {
if (!upgradeDb.objectStoreNames.contains('people')) {
upgradeDb.createObjectStore('people', {keyPath: 'email'});
}
if (!upgradeDb.objectStoreNames.contains('notes')) {
upgradeDb.createObjectStore('notes', {autoIncrement: true});
}
if (!upgradeDb.objectStoreNames.contains('logs')) {
upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement: true});
}
});
复制代码
其中经过 onupgradeneeded
回调获得的 event.result 就是 IDBDatabase
的实例,经常用来设置 index 和插入数据。参考下面内容。
参考:
该对象经常用来作 Object Store 和 transaction 的建立和删除。该部分是 onupgradeneeded
事件得到的 event.target.result
对象:
request.onupgradeneeded = function(event) {
// 更新对象存储空间和索引 ....
// event.target.result 对象
};
复制代码
具体 API 内容以下:
[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
readonly attribute DOMString name;
readonly attribute unsigned long long version;
readonly attribute DOMStringList objectStoreNames;
[NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
optional IDBTransactionMode mode = "readonly");
void close();
[NewObject] IDBObjectStore createObjectStore(DOMString name,
optional IDBObjectStoreParameters options);
void deleteObjectStore(DOMString name);
// Event handlers:
attribute EventHandler onabort;
attribute EventHandler onclose;
attribute EventHandler onerror;
attribute EventHandler onversionchange;
};
dictionary IDBObjectStoreParameters {
(DOMString or sequence<DOMString>)? keyPath = null;
boolean autoIncrement = false;
};
复制代码
若是它经过 createObjectStore 方法,那么获得的就是一个 IDBObjectStore
实例对象。若是是 transaction 方法,那么就是 IDBTransaction
对象。
该对象通常是用来建立 index 和插入数据使用。
能够参考:
[Exposed=(Window,Worker)]
interface IDBObjectStore {
attribute DOMString name;
readonly attribute any keyPath;
readonly attribute DOMStringList indexNames;
[SameObject] readonly attribute IDBTransaction transaction;
readonly attribute boolean autoIncrement;
[NewObject] IDBRequest put(any value, optional any key);
[NewObject] IDBRequest add(any value, optional any key);
[NewObject] IDBRequest delete(any query);
[NewObject] IDBRequest clear();
[NewObject] IDBRequest get(any query);
[NewObject] IDBRequest getKey(any query);
[NewObject] IDBRequest getAll(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest getAllKeys(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest count(optional any query);
[NewObject] IDBRequest openCursor(optional any query,
optional IDBCursorDirection direction = "next");
[NewObject] IDBRequest openKeyCursor(optional any query,
optional IDBCursorDirection direction = "next");
IDBIndex index(DOMString name);
[NewObject] IDBIndex createIndex(DOMString name,
(DOMString or sequence<DOMString>) keyPath,
optional IDBIndexParameters options);
void deleteIndex(DOMString name);
};
dictionary IDBIndexParameters {
boolean unique = false;
boolean multiEntry = false;
};
复制代码
该对象是用来进行 Index 索引的操做对象,里面也会存在 get
和 getAll
等方法。详细内容以下:
[Exposed=(Window,Worker)]
interface IDBIndex {
attribute DOMString name;
[SameObject] readonly attribute IDBObjectStore objectStore;
readonly attribute any keyPath;
readonly attribute boolean multiEntry;
readonly attribute boolean unique;
[NewObject] IDBRequest get(any query);
[NewObject] IDBRequest getKey(any query);
[NewObject] IDBRequest getAll(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest getAllKeys(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest count(optional any query);
[NewObject] IDBRequest openCursor(optional any query,
optional IDBCursorDirection direction = "next");
[NewObject] IDBRequest openKeyCursor(optional any query,
optional IDBCursorDirection direction = "next");
};
复制代码
参考:
idb 开源库,微型代码库 treo 开源库 dexie.js 开源库 indexeddb 原生概念 IndexedDB