在講indexDB之前,先簡單說說cookie、localStorage、sessionStorage。
cookie
Cookie 是小甜餅的意思。顧名思義,cookie 確實非常小,它的大小限制為4KB左右,是網景公司的前雇員 Lou Montulli 在1993年3月的發明。它的主要用途有保存登錄信息,比如你登錄某個網站市場可以看到“記住密碼”,這通常就是通過在 Cookie 中存入一段辨別用戶身份的數據來實現的。
localStorage
localStorage 是 HTML5 標准中新加入的技術,它並不是什么划時代的新東西。早在 IE 6 時代,就有一個叫 userData 的東西用於本地存儲,而當時考慮到瀏覽器兼容性,更通用的方案是使用 Flash。而如今,localStorage 被大多數瀏覽器所支持,如果你的網站需要支持 IE6+,那以 userData 作為你的 polyfill 的方案是種不錯的選擇。
sessionStorage
sessionStorage 與 localStorage 的接口類似,但保存數據的生命周期與 localStorage 不同。 Session 這個詞的意思,直譯過來是“會話”。它只是可以將一部分數據在當前會話中保存下來,刷新頁面數據依舊存在。但當頁面關閉后,sessionStorage 中的數據就會被清空。
Desktop | Chrome | Edge | Firefox | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
localStorage | 4 | Yes | 3.5 | 8 | 10.5 | 4 |
sessionStorage | 5 | Yes | 2 | 8 | 10.5 | 4 |
Mobile | Android webview | Chrome for Android | Edge Mobile | Firefox for Android | Opera for Android | iOS Safari |
---|---|---|---|---|---|---|
localStorage | Yes | Yes | Yes | Yes | 10.5 | 3.2 |
sessionStorage | Yes | Yes | Yes | Yes | 11 | 3.2 |
cookie、localStorage、sessionStorage異同
特性 | Cookie | localStorage | sessionStorage |
---|---|---|---|
數據的生命期 | 一般由服務器生成,可設置失效時間。如果在瀏覽器端生成Cookie,默認是關閉瀏覽器后失效 | 除非被清除,否則永久保存 | 僅在當前會話下有效,關閉頁面或瀏覽器后被清除 |
存放數據大小 | 4K左右 | 一般為5MB | 一般為5MB |
與服務器端通信 | 每次都會攜帶在HTTP頭中,如果使用cookie保存過多數據會帶來性能問題 | 僅在客戶端(即瀏覽器)中保存,不參與和服務器的通信 | 僅在客戶端(即瀏覽器)中保存,不參與和服務器的通信 |
易用性 | 需要程序員自己封裝,源生的Cookie接口不友好 | 源生接口可以接受,亦可再次封裝來對Object和Array有更好的支持 | 源生接口可以接受,亦可再次封裝來對Object和Array有更好的支持 |
接下來就開始上重頭戲了 —— indexDB
indexDB
隨着瀏覽器的功能不斷增強,越來越多的網站開始考慮,將大量數據儲存在客戶端,這樣可以減少從服務器獲取數據,直接從本地獲取數據。
通俗地講,IndexedDB 就是瀏覽器提供的本地數據庫,它可以被網頁腳本創建和操作。IndexedDB 允許儲存大量數據,提供查找接口,還能建立索引。這些都是 LocalStorage 所不具備的。就數據庫類型而言,IndexedDB 不屬於關系型數據庫(不支持 SQL 查詢語句),更接近 NoSQL 數據庫。
操作步驟
查看更多信息參考
- 創建/打開數據庫。
- 在數據庫中創建一個對象倉庫(object store)。
- 啟動一個事務,並發送一個請求來執行一些數據庫操作,像增加或提取數據等。
- 通過監聽正確類型的 DOM 事件以等待操作完成。
- 在操作結果上進行一些操作(可以在 request 對象中找到)
打開數據庫
var db = null; var request = window.indexedDB.open("MyTestDatabase"); request.onerror = function(event) { // 錯誤處理 console.log(' 打開數據庫報錯'); }; request.onsuccess = function(event) { // 成功處理 db = event.target.result; console.log('打開數據庫成功'); };
創建和更新數據庫版本號
如果指定的版本號,大於數據庫的實際版本號,就會發生數據庫升級事件upgradeneeded。這時通過事件對象的target.result屬性,拿到數據庫實例。
var db = null; request.onupgradeneeded = function (event) { db = event.target.result; }
新建數據庫
新建數據庫與打開數據庫是同一個操作。如果指定的數據庫不存在,就會新建。不同之處在於,后續的操作主要在upgradeneeded事件的監聽函數里面完成,因為這時版本從無到有,所以會觸發這個事件。
通常,新建數據庫以后,第一件事是新建對象倉庫(即新建表)。
request.onupgradeneeded = function(event) { db = event.target.result; var objectStore = null; if (!db.objectStoreNames.contains('imgLists')) { objectStore = db.createObjectStore('imgLists', { keyPath: 'id' }); // unique name可能會重復 objectStore.createIndex('name', 'name', { unique: false }); } }
創建一張叫imgLists的表格,主鍵是id。
寫入數據
新增數據指的是向對象倉庫寫入數據記錄。這需要通過事務完成。
// new 一個blob對象 var obj1 = {hello: "world"}; var blob = new Blob([JSON.stringify(obj1, null, 2)], {type : 'application/json'}); function add() { var request = db.transaction(['imgLists'], 'readwrite') .objectStore('imgLists') .add({ id: 1, name: '圖片1', path: '/static/image', blob: blob}); request.onsuccess = function (event) { console.log('數據寫入成功'); }; request.onerror = function (event) { console.log('數據寫入失敗'); } }
查詢數據
查詢數據也是通過事物完成。
function read() { var transaction = db.transaction(['imgLists']); var objectStore = transaction.objectStore('imgLists'); // 用戶讀取數據,參數是主鍵 var request = objectStore.get(1); request.onerror = function(event) { console.log('事務失敗'); }; request.onsuccess = function( event) { if (request.result) { console.log(request.result); } else { console.log('未獲得數據記錄'); } }; }
遍歷數據
遍歷數據表格的所有記錄,要使用指針對象 IDBCursor。
function readAll() { var objectStore = db.transaction('imgLists').objectStore('imgLists'); objectStore.openCursor().onsuccess = function (event) { var cursor = event.target.result; if (cursor) { console.log(cursor); cursor.continue(); } else { console.log('沒有更多數據了!'); } }; }
更新數據
function update() { var request = db.transaction(['imgLists'], 'readwrite') .objectStore('imgLists') // 主動更新主鍵為1 .put({ id: 1, name: '圖片2', path: '/static/image2'}); request.onsuccess = function (event) { console.log('數據更新成功'); }; request.onerror = function (event) { console.log('數據更新失敗'); } }
刪除數據
function remove() { var request = db.transaction(['imgLists'], 'readwrite') .objectStore('imgLists') .delete(1); request.onsuccess = function (event) { console.log('數據刪除成功'); }; } remove();
創建/使用索引
索引的意義在於,可以讓你搜索任意字段,也就是說從任意字段拿到數據記錄。如果不建立索引,默認只能搜索主鍵(即從主鍵取值)。
objectStore.createIndex('name', 'name', { unique: false });
function findIndex() { var transaction = db.transaction(['imgLists'], 'readonly'); var store = transaction.objectStore('imgLists'); var index = store.index('name'); var request = index.get('圖片1'); request.onsuccess = function (e) { var result = e.target.result; if (result) { console.log(result); } else { // ... } } }
使用場景
indexDB是一個瀏覽器使用簡易的數據庫。隨着前端功能復雜度提升,用戶需要多元化,前端indexDB應用也就越來越多。桌面應用、Progressive Web App(PWA)、chrome擴展組件的開發等。用戶同時會獲取/操作更多的信息,怎么留存這些大量的數據,那么我們的indexDB就上線了。案例:DevDocs,electron開發的桌面應用(圖片傳輸)。