前端数据库IndexedDB -2019-08-14

由于之前项目需求,循环播放广告需要对视频、图片做本地存储,以节省移动端流量及播放视频的稳定性,翻阅资料后,找到了IndexedDB

WebSQL DB与IndexedDB

打开chrome,按F12进入调试,切换到Application分页

82A8C1B4-7098-4317-936E-5530D6D4B3C5.png

可以看到,前端数据库有WebSQL DBIndexedDB两种,而Cookies、SessionStorage、LocalStorage都只能存储少量数据,通常只存储一些字符串,在这里不予考虑。

WebSQL DB是一个关系型数据库,使用sql查询语句,可以存储大型数据,但是不支持IE及火狐,其兼容性可以在https://caniuse.com网站中查看,并且W3C规范已经停止对WebSQL DB的维护,将来也可能不再支持。

The Web SQL Database specification is no longer being maintained and support may be dropped in future versions.

所以,项目中并不再推荐使用WebSQL DB
IndexedDb兼容性较之要更好,并且目前也升级到了2.0,W3C也在大力推广其规范,综上考虑项目中就顺理成章的使用了IndexedDb

IndexedDb则是一个非关系型数据库,不支持sql查询,更像是NoSql数据库。虽然其已经升级了2.0,但是兼容性比1.0要差不少,新增功能也只是对api的补全,所以目前只使用1.0版本记录。

IndexedDB 具有以下特点。

  • 键值对储存
    IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。

  • 异步IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。

  • 支持事务IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

  • 同源限制IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

  • 储存空间大IndexedDB 的储存空间比 LocalStorage大得多,一般来说不少于 250MB,甚至没有上限。

  • 支持二进制储存IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob对象)。

实例

1、创建数据库
    this.request = window.indexedDB.open(databaseName, 1);

    this.request.onerror = this.__dbOpenErr;
    this.request.onsuccess = this.__dbOpenSuccess;
    this.request.onupgradeneeded = this.__dbUpgradeneeded;

    this.openCallback = callback;

使用window.indexedDB.open打开数据库,第一个参数是字符串,表示数据库的名字。如果指定的数据库不存在,就会新建数据库。第二个参数是整数,表示数据库的版本。如果省略,打开已有数据库时,默认为当前版本;新建数据库时,默认为1
其返回值,是一个IDBRequest对象,通过onerror , onsuccess , onupgradeneeded三个回调方法处理操作结果。打开数据库成功后,其db对象也在IDBRequest中获取

  __dbOpenErr = (event) => {
    console.log('数据库打开报错');
    if(this.openCallback){
      this.openCallback(false);
    }
  };

  __dbOpenSuccess = (event) => {
    this.db = this.request.result;
    console.log("数据库打开成功");
    if(this.openCallback){
      this.openCallback(true);
    }
  };

成功和失败时,调用callback通知上层。

const databaseName = "IndexedDB";
const storeNames = "Media";
// 数据库升级事件,第一次创建时会走这里
  __dbUpgradeneeded = (event) => {
    this.db = event.target.result;
    let objectStore;
    if (!this.db.objectStoreNames.contains(storeNames)) {
      objectStore = this.db.createObjectStore(storeNames, { keyPath: 'keyPath' });
      // objectStore.createIndex('blob', 'blob', { unique: false });
      objectStore.createIndex('type', 'type', {unique: false});
      objectStore.createIndex('url', 'url', {unique: false});
    }
    // if(this.openCallback){
    //   this.openCallback(true);
    // }
  };

onupgradeneeded是数据库升级事件,当第一次打开数据库,由于数据库不存在也会走这里,所以需要在这里做数据库初始化,创建一个“表”(ObjectStore)。上述代码,先判断了Media是否存在,不存在就创建了一个叫Media的“表”,主键名是keyPath。如果不想指定主键,可以让IndexedDB自动生成主键。

objectStore = this.db.createObjectStore(storeNames, { autoIncrement: true });

下一步是使用IDBObject.createIndex创建索引,三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否 不能重复,为true不可重复,false则可重复)。这里创建了typeurl两个可重复索引。

2、新增数据
insert(data, callback) {
    let request = this.db.transaction([storeNames], 'readwrite')
      .objectStore(storeNames)
      .add(data);

    request.onsuccess = (event) => {
      console.log('数据写入成功');
      if(callback){
        callback(true);
      }
    };

    request.onerror = function (event) {
      console.log('数据写入失败');
      console.log(event);
      if(callback){
        callback(false);
      }
    }
  }

写入数据需要新建一个事务。新建时必须指定表格名称和操作模式(readonlyreadwrite)。新建事务以后,通过IDBTransaction.objectStore(name)方法,拿到IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。

3、读取数据
// 主键搜索
  searchByKeyPath(keyPath, callback){
    let transaction = this.db.transaction([storeNames], 'readonly');
    let store = transaction.objectStore(storeNames);
    let request = store.get(keyPath);

    request.onsuccess = (e) => {
      let result = e.target.result;
      if(callback){
        callback(result);
      }
    };

    request.onerror = (e) => {
      if(callback){
        callback(null);
      }
    };
  }

使用objectStoreget方法读取数据,参数是主键值。如果你没指定主键,那就只能使用索引读取了。

4、索引
  // 索引搜索
  searchByUrl(url, callback) {
    let transaction = this.db.transaction([storeNames], 'readonly');
    let store = transaction.objectStore(storeNames);
    let index = store.index('url');
    // 安卓5.1不支持getAll方法
    let request = index.get(url);

    request.onsuccess = (e) => {
      let result = e.target.result;
      if(callback){
        callback(result);
      }
    };

    request.onerror = (e) => {
      if(callback){
        callback(null);
      }
    };

  }

使用之前创建的url索引进行查询数据,objectStore对象的index方法返回IDBIndex对象,参数是索引名,再使用IDBIndexget方法传入要查询的值,就可以从url中查找到相应值的记录。注意:如果查找到多条记录,并不会返回一个数组,而是通过多次回调onsuccess方法告知上层

End~

写的时候,发现有大量的callback,其实还是应该使用promise重写,碍于最近没太多时间重写与测试,就没动源码。本日记发布也晚了两天,最近在跟hr扯皮、改写简历及准备面试,所以无暇顾及。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容