浏览器里的本地数据库:IndexedDB

本文首发于政采云前端团队博客: 浏览器里的本地数据库:IndexedDB

IndexedDB 是什么

在现代浏览器的本地存储方案中,indexedDB 是一项重要的能力组成, 它是能够在浏览器端使用的本地数据库,能够存储大量数据,提供接口来查询,还能够创建索引,这些都是其余存储方案 Cookie 或者 LocalStorage 没法提供的能力。单从数据库类型来看,IndexedDB 是一个非关系型数据库(不支持经过 SQL 语句操做)。javascript

IndexedDB 的主要概念

IndexedDB 是一个比较复杂的 API 组合,学习它的过程就至关于学习它的各个对象 API 接口,包括如下这些( IDB 指当前操做的数据库实例 ):前端

  • 数据库:IDBDatabase 对象
  • 仓库对象: IDBObjectStore 对象
  • 索引:IDBIndex 对象
  • 事务:IDBTransaction 对象
  • 操做请求:IDBRequest 对象
  • 指针:IDBCursor 对象
  • 主键:IDBKeyRange 对象

在这些 API 中包含一些主要概念:java

  • 数据库:数据库是全部相关数据的基本容器。在同源策略( 协议 + 域名 + 端口 )的前提下,每一个域名下能够新建任意多的数据库。IndexedDB 中有版本概念,这就规定了同一时刻下只有一个版本的数据库存在。
  • 对象仓库:对象仓库 ObjectStore 在 IndexedDB 中对应的是 MYSQL 中的表 Table。
  • 数据:对象仓库中记录的是若干条数据,数据只有主键和数据体两个部分,主键不能重复,能够为自增的整数编号或者数据中指定的一个属性。数据体能够是任意数据类型,不限于对象。
  • 索引:为不一样的属性创建索引能够加快数据的检索。
  • 事务:数据的 CURD (增删查改) 都要经过事务来完成。

经过简单的对比图来理解 IndexedDB 的概念:数据库

对比图

快速起步 IndexedDB

在介绍了 IndexedDB 的主要概念以后,能够经过一个简单实用的 CURD 例子来学习在平常开发中咱们是怎么使用 IndexedDB 的,各个 API 细节往后能够慢慢深刻学习。api

  1. 必不可少的浏览器支持检查:promise

    if(!('indexedDB' in window)){
      console.log('当前浏览器支持 IndexedDB');
      return;
    } else {
      console.log('您的浏览器不支持 IndexedDB')
      // todo 建议升级或者更换其余浏览器
    }
  2. 链接数据库浏览器

    // 数据库实例
    let db;
    // 数据库打开操做,第一个参数是数据库名称, 第二个参数是数据库版本
    let DBRequestLink = window.indexedDB.open('dataBaseName', 1)
    DBRequestLink.onsuccess = function(event) {
      // 获取数据库实例
      db = 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 中呈现四列。spa

  4. 向数据库中添加数据指针

    // 这里的 db 就是第二步中的 db 对象, 
    // transaction api 的第一个参数是数据库名称,第二个参数是操做类型
    let newItem = {
      id: 1,
      name: '徐嘻嘻',
      age: 3,
      sex: 'female'
    };
    let transaction = db.transaction('dataBaseName', "readwrite");
    // 找到对应的存储对象
    let objectStore = transaction.objectStore('person');
    // 添加到数据对象中, 传入javascript对象
    objectStore.add(newItem);

    新建操做是在新建了一个 事务( IDBTransaction 对象)的前提下完成的,传入的数据不须要作任何转换,能够无缝传入 Javascript 对象。

  5. 修改数据库中的数据

    // 这里的 db 就是第二步中的 db 对象, 
    // 新建事务
    let transaction = db.transaction('dataBaseName', "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. 删除数据库中的数据

    // 这里的 db 就是第二步中的 db 对象, 
    // 新建事务
    let transaction = db.transaction('dataBaseName', "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

ZooTeam_QRCode_Search.png

相关文章
相关标签/搜索