indexDB介绍与封装
  8CtDmU74qicX 2023年11月24日 18 0

indexDB介绍与封装
一 前端缓存的发展
Cookie: 内存小4kb,现多用于服务端存一些数据在客户端
localstorage/sessionStorage :5M左右,同步缓存,读取速度较快
Cache Storage 与 serviseWorker 配合使用。 (ios 浏览器 很小,其他浏览器可以无限存)
indexDB:内存基本无上限。异步读取数据,适合用来做离线缓存工具。
二 indexDB简介

  1. indexDB是什么?
    客户端键值对数据库
  2. indexDB解决了什么问题?同其他缓存的优劣势对比?
  • 通过支持多种类型的键,来存储几乎可以是任何类型的值。
  • 支撑事务的可靠性。
  • 支持键值范围查询、索引。
  • 和 localStorage 相比,它可以存储更大的数据量。
    解决了其他客户端缓存的内存不足问题,indexDB基本可以算内存没有上线。优势在于,内存大。劣势在于从磁盘中读取数据后,需要在js 中进行一些数据结构的转化,比如blob 转化为图片数据,这个转化过程是同步的,造成了性能问题。
  1. indexDB现实中应用的场景有哪些?
  2. 配合service-worker做离线缓存。
  3. 客户端文件管理
  4. 用户分片上传缓存,做断网断点续传等
    三 indexDB 基本语法
    基于事务:事务提供了三种模式:readonly、readwrite 和 versionchange;
    飞;
    为什么会有不同类型的事务?
    性能是事务需要标记为 readonly 和 readwrite 的原因。许多 readonly 事务能够同时访问同一存储区,但 readwrite 事务不能。因为 readwrite 事务会“锁定”存储区进行写操作。下一个事务必须等待前一个事务完成,才能访问相同的存储区。
    同一存储区又是指的什么?所以这儿如何来判断访问的连贯性?
    IndexedDB 推荐使用的基本模式:
  5. 打开数据库。
  6. 在数据库中创建一个对象仓库(object store)。
  7. 启动一个事务,并发送一个请求来执行一些数据库操作,像增加或提取数据等。
  8. 通过监听正确类型的 DOM 事件以等待操作完成。
  9. 在操作结果上进行一些操作(可以在 request 对象中找到)。

1.创建/打开数据库连接

// 连接数据库,没有的话进行新建操作; name 数据库的名称, version版本号

let openRequest = indexedDB.open(name, version);

openRequest.onupgradeneeded = function() {

// 初始化版本为0时会触发...执行初始化开始...

const db = event.target.result;

let objectStore;

// 注册表

if (!db.objectStoreNames.contains(tableName)) {

objectStore = db.createObjectStore(tableName, { keyPath });

}

// 新建索引

objectStore.createIndex(key, name, options);

// ...执行初始化结束

// 如果客户端没有数据库则触发

};openRequest.onerror = function() {

console.error("Error", openRequest.error);

};openRequest.onsuccess = function() {

let db = openRequest.result;

// 继续使用 db 对象处理数据库

// 全局保存 db对象,进行事务操作

};


2.事务操作 - 数据的增删查改

// 封装事务 - 增删查改操作

// model 代表事务类型

// action 代表操作类型

// value 代表操作的参数

function transaction(

db,

tableName,

{

model = 'readonly',

action = 'get',

value,

}: {

model?: 'readonly' | 'readwrite' | 'versionchange';

action?: 'get' | 'getAll' | 'delete' | 'deleteAll' | 'add' | 'put';

value?: unknown;

},

): Promise {

return new Promise((resolve, reject) => {

const objectStore = db.transaction([tableName], model)?.objectStore(tableName);

const request = objectStore?.action;

request.onerror = function (e) {

reject(e.target);

};

request.onsuccess = function () {

resolve(request.result || null);

};

});

}

四 indexDB封装成通用函数库

function createDataBase({ dbName, tableName, keyPath, createIndex, version = 1 }): Promise {

return new Promise((resolve, reject) => {

const request = window.indexedDB.open(dbName, version);

request.onerror = function () {

reject(new Error('dataBase open error'));

};request.onsuccess = function () {
  const db = request.result;
  //当数据库版本落后了
  db.onversionchange = function () {
    db.close();
    reject(new Error('Database is outdated, please reload the page.'));
  };
  resolve(db);
};
request.onupgradeneeded = function (event) {
  const db = (event.target as IDBOpenDBRequest)?.result;
  let objectStore;
  // 注:新建表,必须在 onupgradeneeded里进行新建。
  // 新建第一章表格 person表格, 先判断该表是否存在
  if (!db.objectStoreNames.contains(tableName)) {
    objectStore = db.createObjectStore(tableName, { keyPath });
  }
  // 新建索引 - 用于除主键以外的值进行搜索
  if (createIndex.length) {
    for (let i = 0; i < createIndex.length; i++) {
      const { key, name, options } = createIndex[i];
      objectStore.createIndex(key, name, options);
    }
  }
};});

}

// 封装事务

function transaction(

db,

tableName,

{

model = 'readonly',

action = 'get',

value,

}: {

model?: 'readonly' | 'readwrite' | 'versionchange';

action?: 'get' | 'getAll' | 'delete' | 'deleteAll' | 'add' | 'put';

value?: unknown;

},

): Promise {

return new Promise((resolve, reject) => {

const objectStore = db.transaction([tableName], model)?.objectStore(tableName);

const request = objectStore?.action;

request.onerror = function (e) {

reject(e.target);

};

request.onsuccess = function () {

resolve(request.result || null);

};

});

}

class IDB<T, U extends keyof never = string> {

db: IDBDatabase;

tableName: string;

keyPath: U;

constructor({

dbName,

tableName,

keyPath,

createIndex = [],

version = 1,

}: {

dbName: string;

tableName: string;

keyPath: U;

createIndex?: Array<{ name: U; key: U; options?: any }>;

version?: number;

}) {

this.tableName = tableName;

this.keyPath = keyPath;

// 创建indexDB数据库 - dbName 为数据库名称,tableName,为表名,createIndex 为定义主

createDataBase({ dbName, tableName, keyPath, createIndex, version }).then((v) => {

this.db = v;

});

}// 新增数据

add = async (value: T): Promise => {

await transaction(this.db, this.tableName, { model: 'readwrite', action: 'add', value });

};

// 删除数据

delete = async (key: U): Promise => {

await transaction(this.db, this.tableName, { model: 'readwrite', action: 'delete', value: key });

};

// 删除所有数据

deleteAll = async (): Promise => {

await transaction(this.db, this.tableName, { model: 'readwrite', action: 'deleteAll' });

};

// 清空数据

// 删除一张表

deleteTable(tableName: string): void {

this.db.deleteObjectStore(tableName);

}

// 查询数据 - 读取一个数据,通过索引来获取,查询结果满足多条数据时只拿第一个数据

read = async (key: U): Promise => {

return await transaction(this.db, this.tableName, { value: key });

};

// 查询所有数据

readAll = async (): Promise => {

return await transaction(this.db, this.tableName, { action: 'getAll' });

};// 修改数据

// 注:修改没有的数据会进行新增

update = async (value: T): Promise => {

return await transaction(this.db, this.tableName, { action: 'put', model: 'readwrite', value });

};

}export { IDB };
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月24日 0

暂无评论

推荐阅读
8CtDmU74qicX