IndexedDB:瀏覽器裡的本地資料庫
IndexedDB 是什麼
在現代瀏覽器的本地儲存方案中,indexedDB 是一項重要的能力組成, 它是可以在瀏覽器端使用的本地資料庫,可以儲存大量資料,提供介面來查詢,還可以建立索引,這些都是其他儲存方案 Cookie 或者 LocalStorage 無法提供的能力。單從資料庫型別來看,IndexedDB 是一個非關係型資料庫(不支援通過 SQL 語句操作)。
IndexedDB 的主要概念
IndexedDB 是一個比較複雜的 API 組合,學習它的過程就相當於學習它的各個物件 API 介面,包括以下這些( IDB 指當前操作的資料庫例項 ):
資料庫:IDBDatabase 物件
倉庫物件: IDBObjectStore 物件
索引:IDBIndex 物件
事務:IDBTransaction 物件
操作請求:IDBRequest 物件
指標:IDBCursor 物件
主鍵:IDBKeyRange 物件
在這些 API 中包含一些主要概念:
資料庫:資料庫是所有相關資料的基本容器。在同源策略( 協議 + 域名 + 埠 )的前提下,每個域名下可以新建任意多的資料庫。IndexedDB 中有版本概念,這就規定了同一時刻下只有一個版本的資料庫存在。 物件倉庫:物件倉庫 ObjectStore 在 IndexedDB 中對應的是 MYSQL 中的表 Table。 資料:物件倉庫中記錄的是若干條資料,資料只有主鍵和資料體兩個部分,主鍵不能重複,可以為自增的整數編號或者資料中指定的一個屬性。資料體可以是任意資料型別,不限於物件。 索引:為不同的屬性建立索引可以加快資料的檢索。 事務:資料的 CURD (增刪查改) 都要通過事務來完成。通過簡單的對比圖來理解 IndexedDB 的概念:
快速起步 IndexedDB
在介紹了 IndexedDB 的主要概念之後,可以通過一個簡單實用的 CURD 例子來學習在日常開發中我們是怎麼使用 IndexedDB 的,各個 API 細節日後可以慢慢深入學習。
必不可少的瀏覽器支援檢查:
if(!('indexedDB' in window)){
console.log('當前瀏覽器支援 IndexedDB');
return;
} else {
console.log('您的瀏覽器不支援 IndexedDB')
// todo 建議升級或者更換其他瀏覽器
}
連線資料庫
// 資料庫例項
let db;
// 資料庫開啟操作,第一個引數是資料庫名稱, 第二個引數是資料庫版本
let DBRequestLink = window.indexedDB.open('dataBaseName', 1)
DBRequestLink.onsuccess = function(event) {
// 獲取資料庫例項
db = DBRequestLink.result;
// 其他操作
};
// 這個監聽回撥觸發於資料庫首次新建、open資料庫時傳遞新版本(只能比之前傳遞的版本高)
DBRequestLink.onupgradeneeded = function(event) {};
建立資料庫的主鍵和欄位
DBOpenRequest.onupgradeneeded = function(event) {
let db = event.target.result;
// 建立一個數據庫儲存物件,並指定主鍵
let objectStore = db.createObjectStore('person', {
keyPath: 'id',
autoIncrement: true
});
/* 定義儲存物件的資料項
* 第一個引數是建立的索引名稱,可以為空
* 第二個引數是索引使用的關鍵名稱,可以為空
* 第三個引數是可選配置引數,可以不傳,常用引數之一就是 unique ,表示該欄位是否唯一,不能重複
*/
objectStore.createIndex('id', 'id', {
unique: true
});
objectStore.createIndex('name', 'name');
objectStore.createIndex('age', 'age');
objectStore.createIndex('sex', 'sex');
};
在上述操作中,我們先定義了上文中提到的 IDBObjectStore 物件,並指定主鍵為 id ,隨後又通過 createIndex 來建立欄位。值得注意的是雖然建立了四個欄位,但在 IndexedDb 中資料還是分為主鍵 id 和資料主體兩個部分,並不會像 MYSQL 中在 Table 中呈現四列。
向資料庫中新增資料
// 這裡的 db 就是第二步中的 db 物件,
// transaction api 的第一個引數是資料庫名稱,第二個引數是操作型別
let newItem = {
id: 1,
name: '徐嘻嘻',
age: 3,
sex: 'female'
};
let transaction = db.transaction('dataBaseName', "readwrite");
// 找到對應的儲存物件
let objectStore = transaction.objectStore('person');
// 新增到資料物件中, 傳入JavaScript物件
objectStore.add(newItem);
新建操作是在新建了一個 事務( IDBTransaction 物件)的前提下完成的,傳入的資料不需要做任何轉換,可以無縫傳入JavaScript物件。
修改資料庫中的資料
// 這裡的 db 就是第二步中的 db 物件,
// 新建事務
let transaction = db.transaction('dataBaseName', "readwrite");
// 新資料主體
let newRecord = {
id: 1,
name: '徐嘎嘎',
age: 5,
sex: 'male'
};
// 開啟已經儲存的資料物件
let objectStore = transaction.objectStore('person');
// 獲取儲存的對應鍵的儲存物件, 傳入主鍵 id,值為 1
let objectStoreRequest = objectStore.get(1);
// 獲取成功後替換當前資料
objectStoreRequest.onsuccess = function(event) {
// 資料
var record = objectStoreRequest.result;
// 遍歷替換
for (let key in newRecord) {
if (typeof record[key] != 'undefined' || key !== 'id') {
record[key] = newRecord[key];
}
}
// 更新資料庫儲存資料
objectStore.put(record);
};
基本思路是建立一個事務,先找到想要修改的資料主體,然後在更新該資料主體內容。 事務建立邏輯相同,並在建立之後呼叫事務的 get 和 put 操作。
刪除資料庫中的資料
// 這裡的 db 就是第二步中的 db 物件,
// 新建事務
let transaction = db.transaction('dataBaseName', "readwrite");
// 開啟已經儲存的資料物件
let objectStore = transaction.objectStore('person');
// 獲取儲存的對應鍵的儲存物件, 傳入主鍵 id,值為 1
let objectStoreRequest = objectStore.delete(1);
呼叫 delete 介面,傳入指定的 id 即可。
佛山vi設計https://www.houdianzi.com/fsvi/ 豌豆資源搜尋大全https://55wd.com
可以提效的類庫
從上面的例子中可以看出,每一次操作需要至少三行程式碼才能完成,而且需要一直維護 DB 的物件引用,避免它被回收,這樣子開發程式碼膨脹得太厲害,所以我們在業務中引入其他類庫來減少程式碼量
LocalForage 可以指定資料儲存方案,預設依次為 IndexedDB、WebSQL、LocalStorage,意味著當前 IndexedDB 失效可以有兜底措施。 API 簡化為 CRUD ( getItem、removeItem、setItem、clear ) 庫大小為 475b Pouchdb API 簡化為 put、get、remove,基於 promise 來檢查回收錯誤 有較好的錯誤日誌機制, 如失敗,衝突等等,方便除錯 庫大小為 255b這兩個類庫比較符合我們的開發要求,我們當前使用的是 LocalForage。
結束語
在業務開發中,我們都會碰到或多或少的本地儲存需求,本文介紹了其中一種儲存方案 IndexedDB 的簡單實踐。就我們的應用場景來看,IndexedDB 的適用面還是很廣的。考慮到 IE10 也可以支援,把它實踐在實際專案中應該是沒有問題的。