在知乎和我在日常工做中,经常会看到一个问题:前端
前端如今还火吗?
这个我只想说:git
隔岸观火的人永远没法明白起火的缘由,只有置身风暴,才能找到风眼之所在 ——『秦时明月』
你 TM 看都不看前端如今的发展,怎么去评判前端火不火,我该不应尝试一下其余方面的内容呢?本人为啥为这么热衷于新的技术呢?主要缘由在于,生怕会被某一项颠覆性的内容淘汰掉,从前沿领域掉队下来。说句人话就是:穷,因此只能学了...
。因此本文会从头剖析一下 IndexedDB
在前端里面的应用的发展。github
indexedDB 目前在前端慢慢获得普及和应用。它正朝着前端离线数据库技术的步伐前进。之前一开始是 manifest、localStorage、cookie 再到 webSQL,如今 indexedDB 逐渐被各大浏览器承认。咱们也能够针对它来进行技术上创新的开发。好比,如今小视频很是流行,那么咱们能够在用户观看时,经过 cacheStorage 缓存,而后利用 WebRTC 技术实现 P2P 分发的控制,不过须要注意,必定要合理利用大小,否则后果然的很严重。web
indexedDB 的总体架构,是由一系列单独的概念串联而成,所有概念以下列表。一眼看去会发现没有任何逻辑,不过,这里我顺手画了一幅逻辑图,中间会根据 函数 的调用而相互串联起来。chrome
总体逻辑图以下:数据库
下文主要介绍了 indexedDB 的基本概念,以及在实际应用中的实操代码。api
index
、cursor
等高效的索引机制,推荐不要直接将全部数据都取回来,再进行筛选,而是直接利用 cursor
进行。IndexedDB 能够存储很是多的数据,好比 Object,files,blobs 等,里面的存储结构是根据 Database 来进行存储的。每一个 DB 里面能够有不一样的 object stores。具体结构以下图:数组
而且,咱们能够给 key
设定相关特定的值,而后在索引的时候,能够直接经过 key 获得具体的内容。使用 IndexDB 须要注意,其遵循的是同域原则。promise
在 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- $ 2^{53} $],参考 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
key: 这个 key 的值,能够经过三种方式生成。 a key generator, a key path, 用户指定的值。而且,这个 key 在当前的 Object Store 是惟一的。一个 key 类型能够是 string, date, float, and array 类型。不过,在老版本的时候,通常只支持 string or integer。(如今,版本应该都 OK 了)
- key generator: 至关于以一种 `id++` 的形式来生成一个 key 值。 - key path: 当前指定的 key 能够根据 value 里面的内容来指定。里面能够为一些分隔符。 - 指定的 key:这个就是须要用户手动来指定生成。
操做做用域
key range: 用来设置取出数据的 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
也欢迎你们关注个人公众号:前端小吉米 得到一手的技术文章以及将来技术的发展内容。