1. 特點
IndexedDB 是一種可以讓你在用戶的瀏覽器內持久化存儲數據的方法。特點如下:
* 支持事務、遊標、索引等數據庫操作
* 一般瀏覽器會分配50M-250M不等的內存
* 持久化存儲,清除瀏覽器緩存不會被刪除(localStorage是會被刪除的)
* 支持多種數據格式:arrayBuffer、String、Object、Array、File、Blob、ImageData都ok
* 不支持跨域,一個域可以有多個數據庫
* 開發中需要謹記的一個特性:異步操作,換句話說,所有操作都需要在回調函數中完成
2. 兼容性
前端在學一項技術時候,往往先關注它的兼容性,再牛的技術,不兼容也是用不到項目中的。
這是can i use中指示的情況,我實測的結果是:
* PC端chrome 54上有特殊表現(在第一次打開indexedDB時,upgradeneeded事件不觸發),firfox表現正常
* 移動端ios8-ios10 safari支持,但是X5內核不支持;android上X5內核支持
3. 使用
基本使用模式如下:
1. 打開數據庫
2. 建立一個事務
3. 在事務請求的回調函數中處理事務處理的結果
4. 使用完畢關閉數據庫
3.1 基本概念
數據庫
一個數據庫由數據庫名和其版本兩個屬性
事務
事務用於操縱數據庫中數據,每個事務有不同的模式:readonly、readwrite或者versionchange。簡單說下versionchange,在這個事務中,可以讀取、更新、刪除已經存在的數據,也可以刪除和新建對象存儲空間(object stores)和索引。該類型事務不能手動創建,但是在upgradeneeded事件被觸發時會自動創建。
對象存儲空間
object store,我理解類似數據庫的表。一個數據庫會有多個對象存儲空間,對象存儲空間中存儲着數據。
key
每條數據有一個key,這個key可以是每次存儲時用戶自己具體決定某個值,可以是用戶在新建object store時使用傳入對象的某個字段,也可以讓數據庫自己生成。
具體使用如下:
//使用傳入對象的某個字段作爲key
var objectStore = db.createObjectStore("storeName", { keyPath: "proOfObj" });
//使用具體某個字段作爲key
var objectStore = transaction.objectStore("storeName");
//自動生成key
var objectStore = db.createObjectStore("storeName", {autoIncrement: true});
upgradeneeded事件
就是版本號變更觸發的事件。注意,版本號只能增加,不能減少。新建object store的工作必須在這個事件的回調裏寫,至少我測試是必須,如果在打開數據庫的success事件中寫,會報錯。多麼神奇。
3.2 實例代碼
我對你使用indexedDB的提醒就是,記住異步操縱。
class IndexedDB{
constructor(dbName, storeName, version){
this.storeName = storeName;
const indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB;
const request = indexedDB.open(dbName, version);
request.onsuccess = e => {
this.db = e.target.result;
console.log('Init indexedDB successfully');
};
request.onupgradeneeded = e => {
this.db = e.target.result;
if(!this.db.objectStoreNames.contains(storeName)){
this.store = this.db.createObjectStore(storeName);
}
console.log('DB version changed, db version: ', this.db.version);
};
request.onerror = e => {console.info('Can not open indexedDB', e);};
}
get(key, callback){
const transaction = this.db.transaction(this.storeName);
const objectStore = transaction.objectStore(this.storeName);
const request = objectStore.get(key);
request.onerror = e => {console.info('Can not get value', e);};
request.onsuccess = e => {callback(e.target.result);};
}
set(value, key){
let oldValue;
this.get(key, function(res){oldValue = res;});
if(oldValue){
console.info('You should use function update');
}else{
const transaction = this.db.transaction(this.storeName, 'readwrite');
const objectStore = transaction.objectStore(this.storeName);
const request = objectStore.add(value, key);
request.onerror = e => {console.info('Can not add value', e);};
}
}
update(newValue, key){
const oldValue = this.get(key);
if(!oldValue){
console.info('You should use function set');
}else{
const transaction = this.db.transaction(this.storeName, 'readwrite');
const objectStore = transaction.objectStore(this.storeName);
const request = objectStore.put(newValue, key);
request.onerror = e => {console.info('Can not update value', e);};
}
}
remove(key){
const request = this.db.transaction(this.storeName, 'readwrite')
.objectStore(this.storeName)
.delete(key);
request.onerror = e => {console.info('Can not remove value', e);};
}
close(){
this.db.close();
}
}
我這裏對indexedDB的操作做了一個封裝,對get方法異步處理的方式是傳入一個回調,其實也可以使用thunk或者返回一個promise,大家可以自己試試。
參考連接:
https://w3c.github.io/IndexedDB/
https://www.w3.org/TR/IndexedDB/
https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Using_IndexedDB