IndexedDB 实践
大綱
IndexedDB 介紹
indexedDB VS Web SQL
對比
| 兼容性 | 高 | 低(規范已經廢棄,大部分瀏覽器不再支持) |
| 入門門檻 | 低 | 高,需要額外學習 SQL |
| 性能 | 高 | 低 |
由于 Web SQL 的規范已經廢棄,官方說法是因為無法走標準化的流程,大概意思是你都用 SQL 了,本身就是一個標準化的東西,每個瀏覽器實現幾乎一樣,沒有多樣性了,沒法進行標準的演進,所以廢棄了。
具體可以看官方的說明:
Web SQL Database
寫法對比
從上面的寫法可以看出,indexedDB 更適合前端開發,因為不涉及任何的 SQL 語句,而 web SQL 所有的操作基本都是使用 SQL 來完成的。
IndexedDB 核心對象介紹
IDBDatabase 表示數據庫對象,在操作 indexedDB 之前,我們必須指定數據庫。
IDBObjectStore 表示對象倉庫,類似關系型數據庫的表。
IDBRequest: 操作請求對象,indexedDB 每個操作都是異步的,也就是說每個請求會先返回這個這個對象,然后根據這個對象的回調去進行后續的處理。
IDBIndex: 索引,索引主要用來加快數據查詢的效率,但同時會增加存儲的占用,本質上是一種空間換時間的方式。
IDBTransaction: indexedDB 的所有操作都是基于事務的,事務具有 ACID 四大特性。
IDBCursor: 游標對象,主要用來遍歷數據。
IDBKeyRange: 索引范圍對象,主要用來批量查詢數據,或者批量刪除數據的時候使用。
IndexedDB 基本操作
創建數據庫
調用 indexedDB.open 接口來打開或者創建數據庫。
- 數據庫名稱: 必填參數
- 數據庫版本: 可選參數
這個接口第一個參數是數據庫名稱,第二個參數是數據庫版本,如果傳入的數據庫版本比當前的數據庫版本高,就會觸發數據庫版本升級事件。
創建 IDBObjectStore
因為 indexedDB 多有的操作都是基于事務的,所以在創建 ObjectStore 之前,需要先創建一個事務,就是這里的 db.transaction, 第一個參數是事務的名稱,第二個參數是事務的 mode,主要有這幾種。
其中,versionchange 事件由 indexedDB 自動創建,在 upgradeneeded 事件觸發的時候自動創建。
創建 ObjectStore 的時候,可以指定參數,這里主要有兩個可選的參數,一個是 keyPath,這個表示你要使用 value 當中的哪個屬性來作為主鍵,可以是子屬性。如果沒有合適的屬性用來作為主鍵,可以指定 autoIncrement 屬性為 true,這樣 indexed 就會自動幫你生成自增主鍵。不需要你自己維護。那如果兩個都不傳呢?新增的時候由外部通過 add 方法的第二個參數傳入,否則就會報錯。如果兩個都設置的話,keyPath 生效。
新增數據
修改數據
根據自增主鍵更新:
根據 keyPath 更新:
刪除數據
根據主鍵刪除:
因為我們指定了 isbn 為 keyPath,所以這里我們更新的時候就會更加 isbn 去更新數據。
根據 KeyRange 刪除:
| 1 | var request = objectStore.delete(KeyRange); |
注意這里的 KeyRange 是指主鍵的 KeyRange。
查詢
根據主鍵查詢
索引介紹
通過 ObjectStore 對象的 createIndex 索引可以根據指定的屬性來創建索引,上圖中根據 title 屬性來創建一個唯一索引。
如果不指定 unique:true,則表示創建普通的索引。
索引表的結構類似上圖,通過將索引和數據表的 key 關聯起來,這樣查詢的時候,先通過索引找到所有的對應的記錄的 key,然后根據 key 去數據表查詢,加快查詢速度。
根據索引查詢
索引高級用法:IDBKeyRange
通過 IDBKeyRange 對象,可以用來根據索引查詢符合要求的各種數據。上面的列子表示用索引來查詢 title='人月神話'的記錄數據。
indexedDB 事件介紹
-
success:請求成功
-
error:請求失敗
-
abort:事務終止事件(提交事務失敗時觸發)
-
close:數據庫連接關閉(數據庫不正常關閉時觸發)
-
upgradeneeded:數據庫升級成功
-
blocked:請求被阻塞的事件(存在低版本連接時觸發)
-
versionchange: 版本變更事件
打開數據庫流程:
插入數據流程:
通過上面的兩個流程圖,基本上涉及了 indexedDB 中的所有事件。
一個實際例子
在項目中需要如果需要使用 IndexedDB 來存儲離線日志,日志記錄的主要字段有時間戳(ts)和日志內容(msg)??紤]以下場景:
- 根據時間戳范圍查詢日志
- 根據時間戳范圍刪除日志
如果我們直接根據時間戳查詢,我們需要遍歷整個表的數據,依次比較每條記錄的 ts 是否在查詢的范圍內。
既然 indexedDB 可以使用索引,那我們能不能改造下存儲的字段結構,利用上 indexedDB 的索引能力呢?
我們來看個圖:
上面的圖表示將 1 小時分成 4 份,然后用來存儲數據。那為什么 99 是在第一個區域,而 1000 是在第二個區域呢。
其實非常簡單,就是通過取模來實現的,99 / 60 = 1, 1000 / 60 = 16。
這樣我們就可以將連續的數據放到 4 個區間里面去。那再來看下上面的問題,我們是否可以講時間戳也這樣處理呢?
肯定是可以的,我們來看下使用索引之后的實現,添加一個 timeFragment 字段作為索引:
首先需要根據取模后的時間戳值來創建索引
在報錯數據的時候,我們可以通過以下方法來存儲數據:
下面是根據時間戳來刪除數據:
目前的存儲結構:
通過上面的改造,就可以很好的支持時間戳的范圍查詢了。
總結
以上是生活随笔為你收集整理的IndexedDB 实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCO2016 R1B
- 下一篇: 对flashsky印象最深的一段话