模拟实现一个 localStorage

使用indexedDB 模拟实现一个基础的 localStorage

进入正文之前我们先来了解一下,indexedDB的几个基础操作。

  1. IDBOpenDBRequestIndexedDB API的接口使用特定的事件处理程序属性,提供对打开或删除数据库(使用IDBFactory.open和执行IDBFactory.deleteDatabase)的请求结果的访问。

我们可以通过 indexedDB.open(name,version) 打开一个数据库:

name
 数据库的名称。

version(可选)
 用于打开数据库的版本。如果未提供版本且数据库存在,则将打开与数据库的连接而不更改其版本。如果未提供版本,并且数据库不存在,则将使用version创建它1。

var request = window.indexedDB.open("store", 1);

  1. request.upgradeneeded:初始化或version版本需要更新的时候触发。
    我们可以在upgradeneeded函数监听初始化状态,并创建数据库IDBDatabase
request.onupgradeneeded = event => {
	IDBDatabase = event.target.result;
	objectStore = IDBDatabase.createObjectStore(name, options);
	objectStore.createIndex(indexName, keyPath, objectParameters);
};

下面我们来解析一下代码:

创建一个对象存储库(新建表)

objectStore = IDBDatabase.createObjectStore(name, options);

name
 要创建的新对象库的名称。可以使用空名称创建对象存储。

optionalParameters(可选)
keyPath ,主键(key)是默认建立索引的属性。
autoIncrement,如果是true,则对象存储库具有密钥生成器。默认为false

创建一个新索引。

objectStore.createIndex(indexName, keyPath, objectParameters);

indexName
要创建的索引的名称。可以使用空名称创建索引。

keyPath
要使用的索引的主键。请注意,可以创建一个带有空值的索引keyPath,也可以将序列(数组)作为keyPath

optionalParameters(可选)
unique:如果为true,则索引将不允许单个键重复值。

  1. request.onsuccessIDBRequest成功时触发。
    我们可以在onsuccess监听函数里面,更新数据库IDBDatabase,下面对于IDB的操作都会基于此IDBDatabase
IDBDatabase = event.target.result;
  1. IDBTransaction:操作数据表的读写。
    IDBTransaction接口使用事件处理程序属性在数据库上提供了静态的异步事务。所有数据的读取和写入都在事务内完成。
// IDBDatabase.transaction("store", "readwrite");
IDBDatabase.transaction(name, mode);

name
请求的对象库的名称。

mode
设置对象存储库的模式。默认值为readonly

  1. IDBTransaction.objectStore()
    返回一个IDBObjectStore表示对象存储库的对象,该对象存储库属于此事务的范围。
// IDBTransaction.objectStore("store");
IDBTransaction.objectStore(name);

name
请求的对象库的名称。

接下来我们了解下IDB的增删查改

  1. IDBObjectStore.add():新记录添加到对象存储中。
  2. IDBObjectStore.clear():删除所有当前记录。
  3. IDBObjectStore.delete():删除单个记录。
  4. IDBObjectStore.get():从对象存储中检索特定记录。
  5. IDBObjectStore.put():更新对象存储中的现有记录。
  6. IDBObjectStore.openCursor():遍历对象存储中的所有记录。

index.html,添加一个触发按钮

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <button>set</button>
  </body>
</html>

<script src="./localStorageMock.js"></script>

localStorageMock.js

const name = Symbol('localStorageMock');
const localStorageMock = new (class {
  constructor() {
    Object.assign(this, { [name]: {}, db: {}, objectStore: {}, result: '' });
    Object.defineProperties(this, {
      DBOpenRequest: {
        value: window.indexedDB.open('localStorageMock', 1),
        writable: false,
        configurable: false,
      },
    });
    this.DBOpenRequest.onupgradeneeded = event => {
      this.db = event.target.result;
      if (!this.db.objectStoreNames.contains('store')) {
        this.objectStore = this.db.createObjectStore('store', { keyPath: 'name' });
        this.objectStore.createIndex('name', 'name', { unique: false });
      }
    };
    this.DBOpenRequest.onerror = event => console.error(event);
    this.DBOpenRequest.onsuccess = event => {
      this.db = event.target.result;
    };
  }
  /** 获取所有Storage数据列表 */
  readAll() {
    return new Promise(resolve => {
      let objectStore = this.db.transaction('store').objectStore('store');
      let arr = [];
      objectStore.openCursor().onsuccess = event => {
        let cursor = event.target.result;
        if (cursor) {
          arr.push(cursor.value);
          cursor.continue();
          return resolve(arr);
        } else {
          console.log('没有更多数据了!');
        }
      };
    });
  }
  getItem(key) {
    return new Promise((resolve, reject) => {
      let request = this.db
        .transaction(['store'], 'readonly')
        .objectStore('store')
        .index('name')
        .get(key);
      request.onerror = () => reject('事务失败');
      request.onsuccess = function(event) {
        if (request.result) {
          return resolve(request.result);
        } else {
          return reject('未获得数据记录');
        }
      };
    });
  }
  /** 注意隐患,刷新会情况this[name]数据,建议直接setItem */
  add(key, value) {
    console.log(this[name].hasOwnProperty(key));
    if (this[name].hasOwnProperty(key)) {
      return this.setItem(key, value);
    }
    Object.assign(this[name], { [key]: value });
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .add({ name: key, value: value });
    request.onsuccess = event => console.log('数据写入成功', event.target.result);
    request.onerror = err => console.error('数据写入失败', err.target.error);
  }
  removeItem(key) {
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .delete(key);
    request.onsuccess = () => console.log('数据删除成功');
    request.onerror = err => console.error('数据删除失败', err);
  }
  clear() {
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .clear();
    request.onsuccess = () => console.log('数据库清除成功');
    request.onerror = err => console.error('数据库清除失败', err);
  }
  setItem(key, value) {
    let request = this.db
      .transaction(['store'], 'readwrite')
      .objectStore('store')
      .put({ name: key, value: value });
    request.onsuccess = () => console.log('数据写入成功');
    request.onerror = err => console.error('数据写入失败', err);
  }
})();

document.getElementsByTagName('button')[0].addEventListener('click', async function() {
  console.log(localStorageMock);
  await localStorageMock.setItem('小明', '22岁');
  console.log(await localStorageMock.getItem('小明'));
  console.log(await localStorageMock.readAll());
  await localStorageMock.removeItem('小明');
  await localStorageMock.clear();
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值