indexedDB的精华和使用

1,534 阅读4分钟

image.png

什么是indexDB

  • 一个 事务型 数据库系统 【
  • 一个基于 JavaScript 的面向对象数据库
  • 支持索引,可快速查找数据
  • 可以存储 结构化克隆算法 支持的任何对象

不能被结构化克隆算法复制的数据

结构化克隆算法 用于复制复杂 JavaScript 对象的算法,它通过递归输入对象来构建克隆,同时保持先前访问过的引用的映射,以避免无限遍历循环。

  • Error 以及 Function 对象
  • DOM 节点
  • 属性描述符,setters 以及 getters
  • 原形链上的属性

结构化克隆算法支持的类型

  1. JavaScript 类型

  2. Error 类型

仅支持以下 Error 类型:ErrorEvalErrorRangeErrorReferenceErrorSyntaxErrorTypeErrorURIError(或其他会被设置为 Error

indexedDB特点

  • 以键值对方式存储,键可以是二进制对象。

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

  • 支持异步操作,不是基于Promise的异步,而是基于回调函数的异步。

  • 遵循同源策略,每一个数据库对应创建它的域名,网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

  • 存储空间配额很大,一般来说不少于 250MB,甚至没有上限。

indexedDB主要对象模型

image.png

基本操作流程

  1. 打开数据库
  2. 在数据库中创建/对开一个对象仓库
  3. 启动一个事务,并发送一个请求来执行一些数据库操作,像增加或提取数据等
  4. 通过监听事件以等待操作完成
  5. 继续后续的操作

代码示例: 以上代码建议大家复制出来,在本地运行进行调试,效果会更好喔👀

image.png

实用场景

  • 缓存数据,比如游戏数据
  • 缓存图片,脚本,json文件等等静态资源
  • service worker的第三方库,就有利用到indexedDB

indexedDB第三方库

1、localForage

  • localForage 是一个 JavaScript 库,通过简单类似 localStorageAPI 的异步存储来改进你的Web 应用程序的离线体验。它能存储多种类型的数据,而不仅仅是字符串。

  • ocalForage 有一个优雅降级策略,若浏览器不支持 IndexedDB 或 WebSQL,则使用 localStorage。

  • localForage 提供回调 API 同时也支持 ES6 Promises API ,你可以自行选择。

<script src="./localforage.min.js"></script>
<script>
  localforage.config({
    // 指定存储媒介, localStorage, web sql, localStorage
    driver: localforage.INDEXEDDB,
    // 数据库名
    name: "myApp",
    // 版本
    version: 1.0,
    // 配额
    size: 4980736,
    // 对象库名
    storeName: "keyvaluepairs",
    description: "some description",
  });

  // 实例1
  var store = localforage.createInstance({
    name: "nameHere",
  });

  // 实例2
  var store2 = localforage.createInstance({
    name: "otherName",
  });

  (async function () {
    // 实例1存和取
    await store.setItem("key-1", "value-1", console.log);
    const storeValue1 = await store.getItem("key-1");
    console.log("store key-1:", storeValue1);
    // 实例2存和取
    await store2.setItem("key-1", "value-1", console.log);
    const store2Value1 = await store.getItem("key-1");
    console.log("store2 key-1:", storeValue1);

    // 纯二进制
    store.setItem("key-2", new Blob(["sdsd"]));
  })();
</script>

GitHub 地址:github.com/localForage…
中文教程:localforage.docschina.org/

2、dexie.js

解決了原生 indexdb API 的三个主要问题:

  • 不明确的错误处理
  • 糟糕的查询
  • 代码复杂性
<script type="module">
  import Dexie from "./dexie.min.mjs";
  // 实例化
  const db = new Dexie("FriendDatabase");
  db.version(1).stores({
    friends: "++id,name,age",
  });

  try {
    // 添加
    await db.friends.add({ name: "Josephine", age: 21 });
    // 查询
    const youngFriends = await db.friends.where("age").below(25).toArray();
    console.log(`My young friends: ${JSON.stringify(youngFriends)}`);
  } catch (e) {
    console.log(`Error: ${e}`);
  }
</script>

官网文档:dexie.org/docs/API-Re…

3、ZangoDBs

一个类似于 MongoDB 的IndexedDB接口实现,提供了诸如过滤、投影、排序、更新和聚合等大多数MongoDB 常见的特性。

<script src="./zangodb.min.js"></script>
<script>
  let db = new zango.Db('mydb', { people: ['age'] });
  let people = db.collection('people');

  let docs = [
    { name: 'Frank', age: 20 },
    { name: 'Thomas', age: 33 },
    { name: 'Todd', age: 33 },
    { name: 'John', age: 28 },
    { name: 'Peter', age: 33 },
    { name: 'George', age: 28 }
  ];

  people.insert(docs).then(() => {
    return people.find({
      name: { $ne: 'John' },
      age: { $gt: 20 }
    }).group({
      _id: { age: '$age' },
      count: { $sum: 1 }
    }).project({
      _id: 0,
      age: '$_id.age'
    }).sort({
      age: -1
    }).forEach(doc => console.log('doc:', doc));
  }).catch(error => console.error(error));
</script>

GitHub 地址:github.com/erikolson18…

使用教程:indexeddb库 ZangoDB的使用

4、JsStore

一个具备类 SQL 语法的简单和先进的 IndexedDB 封装实现

<script src="./jsstore.min.js"></script>
<script src="./jsstore.worker.js"></script>
<script>
  // 定义数据结构
  function getDbSchema() {
    var table = {
      name: "Student",
      columns: {
        id: {
          primaryKey: true,
          autoIncrement: true,
        },
        name: {
          notNull: true,
          dataType: "string",
        },
        gender: {
          dataType: "number",
          default: "male",
        },
        country: {
          notNull: true,
          dataType: "string",
        },
        city: {
          dataType: "string",
          notNull: true,
        },
      },
    };

    var db = {
      name: "My-Db",
      tables: [table],
    };
    return db;
  }
  // 实例化
  var jsstoreCon = new JsStore.Connection();

  async function initDb() {
    // 创建数据库
    var isDbCreated = await jsstoreCon.initDb(getDbSchema());
    if (isDbCreated) {
      console.log("db created");
    } else {
      console.log("db opened");
    }
    // 添加
    await addStudent();
    // 查询
    var students = await jsstoreCon.select({
      from: "Student",
    });

    console.log("students", students);
  }

  async function addStudent() {
    try {
      var noOfDataInserted = await jsstoreCon.insert({
        into: "Student",
        values: [
          {
            name: "小名",
            gender: 1,
            country: "北京",
            city: "北京",
          },
          {
            name: "小红",
            gender: 0,
            country: "新疆",
            city: "乌鲁木齐",
          },
        ],
      });
    } catch (ex) {
      console.log("addStudent error:", ex.message);
    }
  }

  initDb();
</script>

使用参考:IndexedDB的包装器JsStore - 基础语法