瀏覽器裏的本地數據庫:IndexedDB

原創不易,但願能關注下咱們,再順手點個贊~~

本文首發於政採雲前端團隊博客: 瀏覽器裏的本地數據庫:IndexedDBjavascript

IndexedDB 是什麼

在現代瀏覽器的本地存儲方案中,indexedDB 是一項重要的能力組成, 它是能夠在瀏覽器端使用的本地數據庫,能夠存儲大量數據,提供接口來查詢,還能夠創建索引,這些都是其餘存儲方案 Cookie 或者 LocalStorage 沒法提供的能力。單從數據庫類型來看,IndexedDB 是一個非關係型數據庫(不支持經過 SQL 語句操做)。前端

IndexedDB 的主要概念

IndexedDB 是一個比較複雜的 API 組合,學習它的過程就至關於學習它的各個對象 API 接口,包括如下這些( IDB 指當前操做的數據庫實例 ):java

  • 數據庫:IDBDatabase 對象
  • 倉庫對象: IDBObjectStore 對象
  • 索引:IDBIndex 對象
  • 事務:IDBTransaction 對象
  • 操做請求:IDBRequest 對象
  • 指針:IDBCursor 對象
  • 主鍵:IDBKeyRange 對象

在這些 API 中包含一些主要概念:數據庫

  • 數據庫:數據庫是全部相關數據的基本容器。在同源策略( 協議 + 域名 + 端口 )的前提下,每一個域名下能夠新建任意多的數據庫。IndexedDB 中有版本概念,這就規定了同一時刻下只有一個版本的數據庫存在。api

  • 對象倉庫:對象倉庫 ObjectStore 在 IndexedDB 中對應的是 MYSQL 中的表 Table。promise

  • 數據:對象倉庫中記錄的是若干條數據,數據只有主鍵和數據體兩個部分,主鍵不能重複,能夠爲自增的整數編號或者數據中指定的一個屬性。數據體能夠是任意數據類型,不限於對象。瀏覽器

  • 索引:爲不一樣的屬性創建索引能夠加快數據的檢索。性能優化

  • 事務:數據的 CURD (增刪查改) 都要經過事務來完成。前端工程師

經過簡單的對比圖來理解 IndexedDB 的概念:less

對比圖

快速起步 IndexedDB

在介紹了 IndexedDB 的主要概念以後,能夠經過一個簡單實用的 CURD 例子來學習在平常開發中咱們是怎麼使用 IndexedDB 的,各個 API 細節往後能夠慢慢深刻學習。

  1. 必不可少的瀏覽器支持檢查:

    if('indexedDB' in window){
      console.log('當前瀏覽器支持 IndexedDB');
      return;
    } else {
      console.log('您的瀏覽器不支持 IndexedDB')
      // todo 建議升級或者更換其餘瀏覽器
    }
    複製代碼
  2. 鏈接數據庫

    // 數據庫實例
     let dbInstance;
     // 數據庫打開操做,第一個參數是數據庫名稱, 第二個參數是數據庫版本
     let DBRequestLink = window.indexedDB.open('dataBaseName', 4)
     DBRequestLink.onsuccess = function(event) {
       // 獲取數據庫實例
       dbInstance = DBRequestLink.result;
       // 其餘操做
     };
     // 這個監聽回調觸發於數據庫首次新建、open數據庫時傳遞新版本(只能比以前傳遞的版本高)
     DBRequestLink.onupgradeneeded = function(event) {};
    複製代碼
  3. 建立數據庫的主鍵和字段

    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 中呈現四列。

  4. 向數據庫中添加數據

    // 這裏的 dbInstance 就是第二步中的 dbInstance 對象, 
     // transaction api 的第一個參數是數據庫名稱,第二個參數是操做類型
     let newItem = {
       id: 1,
       name: '徐嘻嘻',
       age: 3,
       sex: 'female'
     };
     let transaction = dbInstance.transaction('person', "readwrite");
     // 找到對應的存儲對象
     let objectStore = transaction.objectStore('person');
     // 添加到數據對象中, 傳入javascript對象
     objectStore.add(newItem);
    複製代碼

    新建操做是在新建了一個 事務( IDBTransaction 對象)的前提下完成的,傳入的數據不須要作任何轉換,能夠無縫傳入 Javascript 對象。

  5. 修改數據庫中的數據

    // 這裏的 dbInstance 就是第二步中的 dbInstance 對象, 
     // 新建事務
     let transaction = dbInstance.transaction('person', "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 操做。

  6. 刪除數據庫中的數據

    // 這裏的 dbInstance 就是第二步中的 dbInstance 對象, 
     // 新建事務
     let transaction = dbInstance.transaction('person', "readwrite");
     // 打開已經存儲的數據對象
     let objectStore = transaction.objectStore('person');
     // 獲取存儲的對應鍵的存儲對象, 傳入主鍵 id,值爲 1 
     let objectStoreRequest = objectStore.delete(1);
    複製代碼

    調用 delete 接口,傳入指定的 id 便可。

能夠提效的類庫

​ 從上面的例子中能夠看出,每一次操做須要至少三行代碼才能完成,並且須要一直維護 DB 的對象引用,避免它被回收,這樣子開發代碼膨脹得太厲害,因此咱們在業務中引入其餘類庫來減小代碼量

  • LocalForage
    • 能夠指定數據存儲方案,默認依次爲 IndexedDB、WebSQL、LocalStorage,意味着當前 IndexedDB 失效能夠有兜底措施。
    • API 簡化爲 CRUD ( getItem、removeItem、setItem、clear )
    • 庫大小爲 475b
  • Pouchdb
    • API 簡化爲 put、get、remove,基於 promise 來檢查回收錯誤
    • 有較好的錯誤日誌機制, 如失敗,衝突等等,方便調試
    • 庫大小爲 255b

這兩個類庫比較符合咱們的開發要求,咱們當前使用的是 LocalForage。

結束語

在業務開發中,咱們都會碰到或多或少的本地存儲需求,本文介紹了其中一種存儲方案 IndexedDB 的簡單實踐。就咱們的應用場景來看,IndexedDB 的適用面仍是很廣的。考慮到 IE10 也能夠支持,把它實踐在實際項目中應該是沒有問題的。

文章內容較長,若是表達有誤在所不免,歡迎交流指出。

招賢納士

招人,前端,隸屬政採雲前端大團隊(ZooTeam),50 餘個小夥伴正等你加入一塊兒浪~ 若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變「5年工做時間3年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手參與一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給ZooTeam@cai-inc.com

推薦閱讀

寫給前端工程師的 Serverless 入門

前端工程實踐之可視化搭建系統(一)

自動化 Web 性能優化分析方案

相關文章
相關標籤/搜索