IndexedDB 學(xué)習(xí)
介紹
IndexedDB 是一個(gè)基于 JavaScript 的面向?qū)ο蟮氖聞?wù)型數(shù)據(jù)庫(kù)。其實(shí)對(duì)于在瀏覽器里存儲(chǔ)數(shù)據(jù),可以使用 cookies 或 LocalStorage,但它們都是比較簡(jiǎn)單的技術(shù),而 IndexedDB 提供了類似數(shù)據(jù)庫(kù)風(fēng)格的數(shù)據(jù)存儲(chǔ)和使用方式。
LocalStorage 與 IndexedDB 區(qū)別也適用場(chǎng)景
LocalStorage 是用 key-value 鍵值模式存儲(chǔ)數(shù)據(jù),它存儲(chǔ)的數(shù)據(jù)都是字符串形式。如果你想讓 LocalStorage存儲(chǔ)對(duì)象,你需要借助 JSON.stringify()能將對(duì)象變成字符串形式,再用 JSON.parse()將字符串還原成對(duì)象,就是專門(mén)為小數(shù)量數(shù)據(jù)設(shè)計(jì)的,所以它的 api 設(shè)計(jì)為同步的。
IndexedDB 很適合存儲(chǔ)大量數(shù)據(jù),它的 API 是異步調(diào)用的。IndexedDB 使用索引存儲(chǔ)數(shù)據(jù),各種數(shù)據(jù)庫(kù)操作放在事務(wù)中執(zhí)行。IndexedDB 甚至還支持簡(jiǎn)單的數(shù)據(jù)類型。IndexedDB 比 localstorage 強(qiáng)大得多,但它的 API 也相對(duì)復(fù)雜。對(duì)于簡(jiǎn)單的數(shù)據(jù),你應(yīng)該繼續(xù)使用 localstorage,但當(dāng)你希望存儲(chǔ)大量數(shù)據(jù)時(shí),IndexedDB 會(huì)明顯的更適合,IndexedDB 能提供你更為復(fù)雜的查詢數(shù)據(jù)的方式。
indexedDB 的特性
- 對(duì)象倉(cāng)庫(kù)
有了數(shù)據(jù)庫(kù)后我們自然希望創(chuàng)建一個(gè)表用來(lái)存儲(chǔ)數(shù)據(jù),但 indexedDB 中沒(méi)有表的概念,而是 objectStore,一個(gè)數(shù)據(jù)庫(kù)中可以包含多個(gè) objectStore,objectStore 是一個(gè)靈活的數(shù)據(jù)結(jié)構(gòu),可以存放多種類型數(shù)據(jù)。也就是說(shuō)一個(gè) objectStore 相當(dāng)于一張表,里面存儲(chǔ)的每條數(shù)據(jù)和一個(gè)鍵相關(guān)聯(lián)。我們可以使用每條記錄中的某個(gè)指定字段作為鍵值(keyPath),也可以使用自動(dòng)生成的遞增數(shù)字作為鍵值(keyGenerator),也可以不指定。選擇鍵的類型不同,objectStore 可以存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)也有差異。
- 事務(wù)性
在 indexedDB 中,每一個(gè)對(duì)數(shù)據(jù)庫(kù)操作是在一個(gè)事務(wù)的上下文中執(zhí)行的。事務(wù)范圍一次影響一個(gè)或多個(gè) object stores,你通過(guò)傳入一個(gè) object store 名字的數(shù)組到創(chuàng)建事務(wù)范圍的函數(shù)來(lái)定義。例如:db.transaction(storeName, 'readwrite'),創(chuàng)建事務(wù)的第二個(gè)參數(shù)是事務(wù)模式。當(dāng)請(qǐng)求一個(gè)事務(wù)時(shí),必須決定是按照只讀還是讀寫(xiě)模式請(qǐng)求訪問(wèn)。
- 基于請(qǐng)求
對(duì) indexedDB 數(shù)據(jù)庫(kù)的每次操作,描述為通過(guò)一個(gè)請(qǐng)求打開(kāi)數(shù)據(jù)庫(kù),訪問(wèn)一個(gè) object store,再繼續(xù)。IndexedDB API 天生是基于請(qǐng)求的,這也是 API 異步本性指示。對(duì)于你在數(shù)據(jù)庫(kù)執(zhí)行的每次操作,你必須首先為這個(gè)操作創(chuàng)建一個(gè)請(qǐng)求。當(dāng)請(qǐng)求完成,你可以響應(yīng)由請(qǐng)求結(jié)果產(chǎn)生的事件和錯(cuò)誤。
- 異步
在 IndexedDB 大部分操作并不是我們常用的調(diào)用方法,返回結(jié)果的模式,而是請(qǐng)求—響應(yīng)的模式,所謂異步 API 是指并不是這條指令執(zhí)行完畢,我們就可以使用 request.result 來(lái)獲取 indexedDB 對(duì)象了,就像使用 ajax 一樣,語(yǔ)句執(zhí)行完并不代表已經(jīng)獲取到了對(duì)象,所以我們一般在其回調(diào)函數(shù)中處理。
幾個(gè)概念
- IDBFactory:數(shù)據(jù)庫(kù)工廠,負(fù)責(zé)打開(kāi)或者創(chuàng)建數(shù)據(jù)庫(kù)
- IDBFactory.open 方法發(fā)送一個(gè)打開(kāi)或者創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)的請(qǐng)求
- IDBFactory.deleteDatabase 方法: 發(fā)送一個(gè)刪除數(shù)據(jù)庫(kù)的請(qǐng)求
- IDBDatabase: 數(shù)據(jù)庫(kù)
- IDBDatabase.close 方法關(guān)閉數(shù)據(jù)庫(kù)。
- IDBDatabase.createObjectStore 方法創(chuàng)建 store,相當(dāng)于表
- IDBDatabase.transaction 開(kāi)啟一個(gè)事務(wù)。
- IDBIndex:數(shù)據(jù)庫(kù)表的索引
- IDBObjectStore:數(shù)據(jù)庫(kù)表
- IDBTransaction:事務(wù)
- IDBRequest:機(jī)會(huì)是所有 indexedDB 操作的返回值,indexedDB 操作請(qǐng)求
- IDBRequest.result 結(jié)果
- IDBRequest.onerror 異常事件
- IDBRequest.onsuccess 成功的事件
快速入門(mén) demo
- 打開(kāi)數(shù)據(jù)庫(kù)實(shí)例。
var db; // 全局的indexedDB數(shù)據(jù)庫(kù)實(shí)例。
//1\. 獲取IDBFactory接口實(shí)例(文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory)
var indexedDB =
window.indexedDB ||
window.webkitIndexedDB ||
window.mozIndexedDB ||
window.msIndexedDB;
if (!indexedDB) {
console.log('你的瀏覽器不支持IndexedDB');
}
// 2\. 通過(guò)IDBFactory接口的open方法打開(kāi)一個(gè)indexedDB的數(shù)據(jù)庫(kù)實(shí)例
// 第一個(gè)參數(shù): 數(shù)據(jù)庫(kù)的名字,第二個(gè)參數(shù):數(shù)據(jù)庫(kù)的版本。返回值是一個(gè):IDBRequest實(shí)例,此實(shí)例有onerror和onsuccess事件。
var IDBOpenDBRequest = indexedDB.open('demoDB', 1);
// 3\. 對(duì)打開(kāi)數(shù)據(jù)庫(kù)的事件進(jìn)行處理
// 打開(kāi)數(shù)據(jù)庫(kù)成功后,自動(dòng)調(diào)用onsuccess事件回調(diào)。
IDBOpenDBRequest.onsuccess = function(e) {};
// 打開(kāi)數(shù)據(jù)庫(kù)失敗
IDBOpenDBRequest.onerror = function(e) {
console.log(e.currentTarget.error.message);
};
// 第一次打開(kāi)成功后或者版本有變化自動(dòng)執(zhí)行以下事件:一般用于初始化數(shù)據(jù)庫(kù)。
IDBOpenDBRequest.onupgradeneeded = function(e) {
db = e.target.result; // 獲取到 demoDB對(duì)應(yīng)的 IDBDatabase實(shí)例,也就是我們的數(shù)據(jù)庫(kù)。
if (!db.objectStoreNames.contains(personStore)) {
//如果表格不存在,創(chuàng)建一個(gè)新的表格(keyPath,主鍵 ; autoIncrement,是否自增),會(huì)返回一個(gè)對(duì)象(objectStore)
// objectStore就相當(dāng)于數(shù)據(jù)庫(kù)中的一張表。IDBObjectStore類型。
var objectStore = db.createObjectStore(personStore, {
keyPath: 'id',
autoIncrement: true
});
//指定可以被索引的字段,unique字段是否唯一。類型: IDBIndex
objectStore.createIndex('name', 'name', {
unique: true
});
objectStore.createIndex('phone', 'phone', {
unique: false
});
}
console.log('數(shù)據(jù)庫(kù)版本更改為: ' + dbVersion);
};
- 數(shù)據(jù)庫(kù)的 objectStore 添加
indexedDB 的增刪改查的操作需要放到一個(gè)事務(wù)中進(jìn)行(推薦)
// 創(chuàng)建一個(gè)事務(wù),類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction
var transaction = db.transaction(personStore, 'readwrite');
// 通過(guò)事務(wù)來(lái)獲取IDBObjectStore
var store = transaction.objectStore(personStore);
// 往store表中添加數(shù)據(jù)
var addPersonRequest = store.add({
name: '老馬',
phone: '189111833',
address: 'aicoder.com'
});
// 監(jiān)聽(tīng)添加成功事件
addPersonRequest.onsuccess = function(e) {
console.log(e.target.result); // 打印添加成功數(shù)據(jù)的 主鍵(id)
};
// 監(jiān)聽(tīng)失敗事件
addPersonRequest.onerror = function(e) {
console.log(e.target.error);
};
- 數(shù)據(jù)庫(kù)的 objectStore 修改
// 創(chuàng)建一個(gè)事務(wù),類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction
var transaction = db.transaction(personStore, 'readwrite');
// 通過(guò)事務(wù)來(lái)獲取IDBObjectStore
var store = transaction.objectStore(personStore);
var person = {
id: 6,
name: 'lama',
phone: '515154084',
address: 'aicoder.com'
};
// 修改或者添加數(shù)據(jù)。 第一參數(shù)是要修改的數(shù)據(jù),第二個(gè)參數(shù)是主鍵(可省略)
var updatePersonRequest = store.get(6);
// 監(jiān)聽(tīng)添加成功事件
updatePersonRequest.onsuccess = function(e) {
// var p = e.target.result; // 要修改的原對(duì)象
store.put(person);
};
// 監(jiān)聽(tīng)失敗事件
updatePersonRequest.onerror = function(e) {
console.log(e.target.error);
};
- 數(shù)據(jù)庫(kù)的 objectStore 刪除
// 創(chuàng)建一個(gè)事務(wù),類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction
var transaction = db.transaction(personStore, 'readwrite');
// 通過(guò)事務(wù)來(lái)獲取IDBObjectStore
var store = transaction.objectStore(personStore);
store.delete(6).onsuccess = function(e) {
console.log(刪除成功!)
};
- 根據(jù) id 獲取數(shù)據(jù)
// 創(chuàng)建一個(gè)事務(wù),類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction
var transaction = db.transaction(personStore, 'readwrite');
// 通過(guò)事務(wù)來(lái)獲取IDBObjectStore
var store = transaction.objectStore(personStore);
store.get(6).onsuccess = function(e) {
console.log(刪除成功!)
};
- 數(shù)據(jù)庫(kù)的 objectStore 游標(biāo)查詢
var trans = db.transaction(personStore, 'readwrite');
var store = trans.objectStore(personStore);
var cursorRequest = store.openCursor();
cursorRequest.onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
var html = template('tbTmpl', cursor.value);
document.getElementById('tbd').innerHTML += html;
cursor.continue(); // 游標(biāo)繼續(xù)往下 搜索,重復(fù)觸發(fā) onsuccess方法,如果到最后返回null
}
};