瀏覽器儲存之爭
資料儲存一直是前端的軟肋,從 4KB 左右的 Cookie 到最多 10MB 的 Storage,儲存之爭從未停止。然而有些問題還是不能解決,這時候我們遇見了她:IndexedDB。
一、前端儲存困境
隨著業務場景的深入,前端對資料儲存有了更高的要求,更多的問題也逐漸暴露出來。
1.儲存空間小
2.無法搜尋資料
3.大量資料如何儲存
4.無法提供事務支援
二、目前儲存方式
1. Cookie
-
Cookie
的大小不超過4KB,且每次請求都會發送回伺服器,佔用額外的流量; - 此外,
Cookies
只能是字串; - 瀏覽器裡儲存
Cookies
的空間有限,很多使用者禁止瀏覽器使用Cookies
; -
Safari
中Cookie
不能儲存中文字元;
所以,Cookies 只能用來儲存小量的非關鍵的資料。
2. Storage
-
LocalStorage
在2.5MB
到10MB
之間(各家瀏覽器不同); - 不提供搜尋功能;
- 不能建立自定義的索引;
-
LocalStorage
是用key-value
鍵值模式儲存資料,它儲存的資料都是字串形式; -
Localstorage
就是專門為小數量資料設計的,它的api
是同步的;
3.
WebSQL
也是一種在瀏覽器裡儲存資料的技術,跟 IndexedDB
不同的是, IndexedDB
更像是一個 NoSQL
資料庫,而 WebSQL
更像是關係型資料庫,使用 SQL
查詢資料。
This document was on the W3C Recommendation track but specification work has stopped. The specification reached an impasse: all interested implementors have used the same SQL backend (Sqlite), but we need multiple independent implementations to proceed along a standardisation path.
W3C
已經不再支援這種技術。
鑑於以上問題,一種新的儲存手段是迫切需要的,以此解決現有儲存的不足之處。
三、如何解決?
那麼既然丟擲了這麼多問題,我們有沒有什麼處理的手段呢?
IndexedDB
提供了一個解決方案。
IndexedDB
是一種瀏覽器端文件資料庫,可以被網頁尾本程式建立和操作。它允許儲存大量資料,並且提供查詢介面,且可以建立索引。
IndexedDB
是一種低階 API
,用於客戶端儲存大量結構化資料(包括, 檔案/ blobs
)。該 API
使用索引來實現對該資料的高效能搜尋。雖然 Web Storage
對於儲存較少量的資料很有用,但對於儲存更大量的結構化資料來說,這種方法不太有用。
IndexedDB
不屬於關係型資料庫(不支援 SQL
查詢語句),更接近 NoSQL
資料庫。
四、相容性
在對某個技術進行嘗試前,我們可能最關心的是他的相容性。

上圖可以看出,幾乎所有瀏覽器都對 indexedDB
有了不錯的支援,所以可以放心大膽的去在你的專案中使用。
五、indexedDB 特點
1.鍵值對儲存
IndexedDB
內部採用物件倉庫 object store
存放資料。所有型別的資料都可以直接存入,包括 JavaScript
物件。物件倉庫中,資料以「鍵值對」的形式儲存,每一個數據記錄都有對應的主鍵。
主鍵是獨一無二的,不能有重複,否則會丟擲一個錯誤。
2.屬於非同步操作
IndexedDB
操作時不會鎖死瀏覽器,使用者依然可以進行其他操作,這與 LocalStorage
形成對比,因為後者是同步操作。
非同步設計是為了防止大量資料的讀寫,拖慢網頁的表現。
3.支援事務
IndexedDB
支援事務 transaction
,這意味著一系列操作步驟之中,只要有一步失敗,整個事務就都取消,資料庫回滾到事務發生之前的狀態,不存在只改寫一部分資料的情況。
4.同源限制
IndexedDB
受到同源限制,每一個數據庫對應建立它的域名。
網頁只能訪問自身域名下的資料庫,而不能訪問跨域的資料庫。
5.儲存空間大
IndexedDB
的儲存空間比 LocalStorage
大得多,一般來說不少於 250MB
,甚至沒有上限。
6.支援二進位制儲存
IndexedDB
不僅可以儲存字串,還可以儲存二進位制資料 ArrayBuffer
物件和 Blob
物件。
六、應用場景
當一個技術出現在你眼前,可能大家會有同樣的疑問:
他的應用場景是什麼,是否適合我的應用程式?
1.你的使用者通過瀏覽器訪問您的應用程式(瀏覽器)支援 IndexedDB API
嗎 ?
2.你需要儲存大量的資料在客戶端?
3.你需要在一個大型的資料集合中快速定位單個數據點嗎?
4.你的架構在客戶端需要事務支援嗎?
如果你有上面幾條提到的需求, IndexedDB
可能是你很好的選擇。
七、快速開始
1.使用前,需要進行必要的判空處理
if(!window.indexedDB) { console.log('你的瀏覽器不支援 IndexedDB '); }
2.我們來建立一個請求開啟 IndexedDB
let request = window.indexedDB.open('jarttoDB', 2);
第一個引數是資料庫的名稱,第二個引數是資料庫的版本號。版本號可以在升級資料庫時用來調整資料庫結構和資料。當我們增加資料庫版本號時,會觸發 onupgradeneeded
事件,這時可能會出現成功、失敗和阻止事件三種情況。
let db; request.onerror = (event) => { console.log('Error', event); } request.onupgradeneeded = (event) => { console.log('Upgrading'); db = event.target.result; let objectStore = db.createObjectStore('blogs', { keyPath : 'rollNo' }); }; request.onsuccess = (event) => { db = event.target.result; console.log('Success', db); }
onupgradeneeded
事件在第一次開啟頁面初始化資料庫時會被呼叫,或在當有版本號變化時。所以,我們應該在 onupgradeneeded
函式裡建立儲存資料。
如果沒有版本號變化,而且頁面之前被開啟過,這時候就會獲得一個 onsuccess
事件。如果有錯誤發生時則觸發 onerror
事件;如果你之前沒有關閉連線,則會觸發 onblocked
事件;
大致套路如此,下面我們來一個完整的資料操作演練一下。
八、CRUD
1.增:為了往資料庫裡新增資料,我們首先需要建立一個事務,並要求具有讀寫許可權。在 indexedDB
裡任何的存取物件的操作都需要放在事務裡執行。
let transaction = db.transaction(['blogs'],'readwrite'); transaction.oncomplete = (event) => { console.log('Success'); }; transaction.onerror = (event) => { console.log('Error'); }; let objectStore = transaction.objectStore('blogs'); objectStore.add({rollNo: rollNo, name: name});
2.刪:刪除跟新增一樣,需要建立事務,然後呼叫刪除介面,通過 key
刪除物件。
db.transaction(['blogs'],'readwrite').objectStore('blogs').delete(rollNo);
3.改:為了更新一個物件,首先要把它取出來,修改,然後再放回去。
let transaction = db.transaction(['blogs'],'readwrite'); let objectStore = transaction.objectStore('blogs'); let request = objectStore.get(rollNo); request.onsuccess = (event) => { console.log(`Updating : ${request.result.name}`); request.result.name = name; objectStore.put(request.result); };
4.查:往 get()
方法裡傳入物件的 key
值,取出相應的物件。
let request = db.transaction(['blogs'],'readwrite').objectStore('blogs').get(rollNo); request.onsuccess = (event) => { console.log(`Name : ${request.result.name}`); };
九、總結
我們從瀏覽器的儲存說起,引出了前端儲存的一系列問題。之後通過簡單的 IndexedDB
介紹,以及實際的 CRUD
操作來全面瞭解 IndexedDB
。當然,這些還只是皮毛,我們還有很長的路要走。
本篇文章主要起到入門學習作用,如果你只想簡單瞭解一下,那麼看到這裡就可以了。如果你想要深入學習,那麼請移步我的下一篇文章: 深入學習 IndexedDB 。