为了账号安全,请及时绑定邮箱和手机立即绑定

indexedDB

  1. 背景

为了实现客户端缓存,虽然已经有很多技术被不断推出和应用,但是随着浏览器功能的不断增强和完善,现有的缓存技术,其局限性也变得越来越明显:

  • 容量太小: cookie和Web Storage最多也就支持5M,已经不能满足需求了
  • 检索不方便: cookie和Web Storage都是以字符串形式存储数据,复杂对象数据存取前需要做处理,比较麻烦
  • 其它问题:不能提供搜索功能,不能建立自定义的索引

这些就是 IndexedDB(Indexed DataBase)诞生的背景,从字面上可以看出,这就是浏览器提供的本地数据库。IndexedDB可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 Web Storage 所不具备的。

  1. 特点

  • 键值对储存: IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
  • 异步: IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
  • 支持事务: IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
  • 同源限制: IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
  • 储存空间大: IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
  • 支持二进制储存: IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
  1. 使用

  • 创建数据库
// 创建或打开数据库
const myDB = window.indexedDB.open('myDB', 1);
// 数据库连接成功
myDB.addEventListener('success', e => {
  console.log("数据库连接成功~");
});
// 数据库连接失败
myDB.addEventListener('error', e => {
  console.log("数据库连接失败~");
});
  • 创建对象仓库

对象仓库(Object Store)是 indexedDB 数据库的基础,熟悉数据库的朋友都知道数据库表的含义,这个对象仓库(以下统一简称仓库)其实就类似于数据库中表的概念。

const myDB = indexedDB.open('myDB', 2);

myDB.addEventListener('upgradeneeded', e => {
  const dbResult = e.target.result;
  // 创建一个"用户信息"仓库 UserInfo
  const createdStore = dbResult.createObjectStore(
    'UserInfo',
    {
      keyPath: 'id',
      autoIncrement: false
    }
  );
});
  • 创建事务
  1. 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。(原子性的意思是每次操作都可以是最小单元,即是可回退也可执行)
    
  2. 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
    
  3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
    
  4. 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
    
const myDB = indexedDB.open('myDB', 3);

myDB.addEventListener('success', e => {
  const dbResult = e.target.result;
  const dbTrans = dbResult.transaction('UserInfo', 'readwrite');
});
  • 数据操作

在数据操作前首先是获取事务对象,通过事务对象的objectStore()方法获取具体的仓库

// 打开数据库,获取dbResult对象
// ...
// 创建事务
const dbTrans = dbResult.transaction(['UserInfo'], 'readwrite');
// 获取仓库
const dbStore = dbTrans.objectStore('UserInfo');
// 后续其他操作
// ...
  1. 新增数据: 即往仓库中添加一条新数据
// 使用add()方法,参数为一条数据对象
const dbRequest = dbStore.add({
  id: 1,
  name: '张三',
  age: 20,
  email: 'zhangsan@example.com'
});
dbRequest.onsuccess = e => {
  console.log('数据添加成功~');
};
dbRequest.onerror = e => {
  console.log('数据添加失败~');
};
  1. 查找数据: 即查找数据仓库中某一条数据
// 使用get()方法,参数为主键的值,即示例中id==1的数据
const dbRequest = dbStore.get(1);
dbRequest.onsuccess = e => {
  const { result } = dbRequest;
  if (result) {
    const { name, age, email } = result;
    console.log('name:', name);
    console.log('age:', age);
    console.log('email:', email);
  } else {
    console.log('未查到对应数据');
  }
};
dbRequest.onerror = e => {
  console.log('数据查询失败~');
};
  1. 遍历数据 即遍历数据表格的一批记录,要使用指针(又称游标)对象IDBCursor。
const myDB = indexedDB.open('myDB', 4);

myDB.addEventListener('success', e => {
  const dbResult = e.target.result;

  const dbTrans = dbResult.transaction('UserInfo');

  const dbStore = dbTrans.objectStore('UserInfo');

  const boundRange = IDBKeyRange.bound(1,5);

  const dbRequest = dbStore.openCursor(boundRange, 'next');

  dbRequest.onsuccess = e => {
    const dbCursor = dbRequest.result || e.target.result;
    if (dbCursor){
      const { key, value } = dbCursor;
      console.log('id:', key);
      console.log('name:', value.name);
      console.log('age:', value.age);
      console.log('email:', value.email);
      dbCursor.continue();
    } else {
        console.log('编辑完毕~');
    }
  };
});
  1. 删除数据 即删除仓库中的某一条数据
// 使用delete()方法,参数为主键的值
const dbRequest = dbStore.delete(1);
dbRequest.onsuccess = e => {
  console.log('数据删除成功~');
};
dbRequest.onerror = e => {
  console.log('数据删除失败~');
};
  1. 更新数据 即修改仓库中的某一条数据
// 使用put()方法,参数为一条数据对象
const dbRequest = dbStore.put({
  id: 1,
  name: '李四',
  age: 22,
  email: 'lisi@example.com'
});
dbRequest.onsuccess = e => {
  console.log('数据更新成功~');
};
dbRequest.onerror = e => {
  console.log('数据更新失败~');
};
  1. 索引查询数据
const myDB = indexedDB.open('myDB', 5);
myDB.addEventListener('upgradeneeded', e => {
  const dbResult = e.target.result;
  // 创建一个"用户信息"仓库 UserInfo
  const createdStore = dbResult.createObjectStore(
    'UserInfo',
    {
      keyPath: 'id',
      autoIncrement: false
    }
  );
  // 创建索引,索引值为ageIndex,对应的键名(或称属性)为age
  createdStore.createIndex(
    'ageIndex',
    'age', 
    {
      unique: false
    }
  );
});

createIndex(indexName, pathKey, options)方法接收三个参数:

indexName: 要创建的索引名,该值唯一,不可重复
pathKey: 仓库里需要建立索引的目标键名(key),或者多个键名组成的数组
options: 是一个可选的配置参数对象,有unique和multiEntry两个值
unique: 用来指定索引值是否可以重复,为true代表不能相同,为false时代表可以相同
multiEntry: 当第二个参数keyPath为一个数组时,如果multiEntry是true,则会以数组中的每个元素建立一条索引,如果是false,则以整个数组为keyPath值,添加一条索引.

const myDB = indexedDB.open('myDB', 4);

myDB.addEventListener('success', e => {

  const dbResult = e.target.result;

  const dbTrans = dbResult.transaction('UserInfo');

  const dbStore = dbTrans.objectStore('UserInfo');

  const lowerBound = IDBKeyRange.lowerBound(20);

  const indexStore = dbStore.index('ageIndex');

  const dbRequest = indexStore.openCursor(lowerBound, 'next');

  dbRequest.addEventListener('success', e => {
    const dbCursor = e.target.result;
    if (dbCursor) {
      const { key, value } = dbCursor;
      console.log('id:', key);
      console.log('name:', value.name);
      console.log('age:', value.age);
      console.log('email:', value.email);
      dbCursor.continue();
    } else {
      console.log('编辑完毕~');
    }
  })
});
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消