浏览器本地存储的indexedDB使用封装
前端使用IndexedDB存储数据的介绍和封装
IndexedDB是一个事务型数据库系统,类似于基于SQL的RDBMS。 然而不同的是它使用固定列表(只有 key,value),IndexedDB是一个基于JavaScript的面向对象的数据库。
IndexedDB允许您存储和检索用键索引的对象; 可以存储structured clone algorithm支持的任何对象。
您只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务中的数据。
虽然indexedDB的使用很方便,存储时间也长,空间也大,但是还是需要注意一些事项
1. 数据类型
IndexedDB 允许存储多种数据类型,包括:
- 基本类型:例如
string、number、boolean和Date。 - 对象类型:如 JavaScript 对象(即普通的对象字面量)。
- 二进制数据:通过
Blob和ArrayBuffer存储二进制数据,适合存储文件、图片、音频等。 - 集合类型:如
Array或Map等,但它们会在存储时转换为对象形式。
不过需要注意:
- 不支持直接存储某些 JavaScript 类型,比如
Function、undefined和RegExp等。 - 不支持循环引用的对象,即包含自引用的对象或深度过大的对象。
2. 键值对存储
IndexedDB 使用 键值对(key-value)存储数据。存储的数据通常包括:
- 键(Key):用于唯一标识数据项。键可以是整数、字符串、
Date或者由 JavaScript 对象提供的自动生成值。 - 值(Value):存储的数据对象或基本数据类型。值可以是任何合法的 JavaScript 数据类型。
存储时,每个对象必须有一个唯一的键,并且键值对的存储是通过事务进行的,以确保数据的一致性。
3. 事务(Transaction)
IndexedDB 是基于事务的数据库,每次对数据的操作都会在事务中进行。每个事务包含一组对数据库的读写操作,保证操作的原子性(即所有操作要么都成功,要么都失败)。
- 事务的隔离性:事务内的数据操作是隔离的,即它不会与其他事务的数据操作产生冲突,直到事务被提交。
- 事务的可读写:事务可以是只读(
readonly)或可读写(readwrite),对于修改数据的操作需要使用可读写事务。
4. 索引(Index)
你可以为对象存储(object store)中的数据创建一个或多个索引,以便根据某个字段或属性快速查找数据。
- 索引的作用:索引允许你根据某个属性高效地查询数据,而无需遍历整个存储。
- 索引类型:索引可以是单一属性的(例如根据
name查询)或复合索引(多个属性组合起来作为查询条件)。
5. 存储空间限制
IndexedDB 的存储空间在不同浏览器和设备中有所不同。通常,存储空间没有明确的硬性限制,而是基于浏览器和设备的存储策略:
- 浏览器限制:不同浏览器对 IndexedDB 存储大小的限制不同,Chrome、Firefox 和 Safari 等主流浏览器一般会限制在一定大小范围内(如 5MB、50MB 或 100MB 等)。
- 设备限制:移动设备可能有更严格的存储限制,尤其在存储和下载文件时需要考虑设备的存储空间。
6. 异步操作
IndexedDB 的所有操作都是异步的,包括打开数据库、执行事务、存储数据、查询数据等。它通过事件和回调函数来通知操作的完成状态。常见的回调方法有:
onsuccess: 当操作成功时调用。onerror: 当操作失败时调用。
这种设计避免了阻塞浏览器的主线程,尤其在进行大数据存储时非常有用。
7. 版本控制(Versioning)
IndexedDB 支持数据库的版本控制。如果你需要更改数据库的结构(例如添加、删除对象存储或修改索引),必须通过数据库的版本升级进行。
- 版本升级:在打开数据库时,如果检测到版本号发生变化,
onupgradeneeded事件会被触发,你可以在这个事件中进行数据库结构的更改。 - 每个数据库都有一个版本号,并且可以对数据库进行结构更新。
8. 支持的数据操作
IndexedDB 支持基本的增删改查操作:
- 添加(Add):向对象存储中添加数据。
- 更新(Put):更新现有数据或替换数据。
- 删除(Delete):删除指定键的数据。
- 查询(Get):根据键值查询数据。
- 游标(Cursor):使用游标遍历存储中的所有数据。
9. 错误处理
虽然 IndexedDB 通常运行时不会阻塞,但它会通过回调的 onerror 方法提供错误信息。常见的错误类型包括:
ConstraintError:违反了数据库的约束条件,如重复键值。DataError:数据格式不正确。TransactionInactiveError:在事务无效时进行操作。
10. 多线程支持
IndexedDB 的操作是异步的,并且可以在浏览器的多个线程之间共享数据。例如,Web Workers 可以使用 IndexedDB 存储和读取数据,从而避免阻塞主线程。
11. 兼容性
大多数现代浏览器都支持 IndexedDB(如 Chrome、Firefox、Edge、Safari 等)。不过,某些老版本的浏览器可能不完全支持或存在已知的 bug,导致部分功能不可用。你可以通过 indexedDB 对象检查浏览器是否支持 IndexedDB。
我们在这里将indexedDB封装成混入js方便在不同页面使用
1.先新建glbCacheMixin.js
// glbCacheMixin.js
export const glbCacheMixin = {
methods: {
// 打开 IndexedDB 数据库
openDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('GLBCacheDB', 1);
request.onupgradeneeded = function (event) {
const db = event.target.result;
if (!db.objectStoreNames.contains('models')) {
db.createObjectStore('models', { keyPath: 'id' }); // 使用 id 作为主键
}
};
request.onsuccess = function (event) {
resolve(event.target.result);
};
request.onerror = function (event) {
reject('IndexedDB open failed');
};
});
},
// 缓存文件到 IndexedDB
cacheGLB(id, Object) {
this.openDB().then(db => {
const transaction = db.transaction('models', 'readwrite');
const store = transaction.objectStore('models');
store.put({ id, data: Object }); // 存储文件,key 是 id
}).catch(error => console.error('Failed to cache GLB:', error));
},
// 从 IndexedDB 中根据 ID 获取缓存的文件
getGLBById(id) {
return new Promise((resolve, reject) => {
this.openDB().then(db => {
const transaction = db.transaction('models', 'readonly');
const store = transaction.objectStore('models');
const request = store.get(id); // 按 ID 获取缓存的文件
console.log('request :>> ', request);
request.onsuccess = function () {
if (request.result) {
resolve(request.result.data); // 返回缓存的文件数据
} else {
resolve(null); // 没有找到缓存
}
};
request.onerror = function () {
reject('出现错误!');
};
});
});
},
// 检查是否已经缓存文件
isGLBCached(id) {
return this.getGLBById(id).then(data => data !== null);
}
}
};
那么我们在页面中使用
//导入
import { glbCacheMixin } from '@/mixins/glbCacheMixin'; // 导入混入
//注册
mixins: [glbCacheMixin],//此级和data并列
//这个方法是用来检测需要缓存的文件地址是否有效
checkResource(url) {
return fetch(url, { method: 'HEAD' }) // 使用 HEAD 请求避免下载整个文件
.then(response => {
if (response.status === 404) {
console.log(`资源未找到: ${url}`);
return false; // 资源不存在
}
return true; // 资源存在
})
.catch(error => {
console.error('检查资源失败:', error);
return false; // 请求出错或其他问题
});
}
//使用
this.checkResource(url)
.then(isValid => {
if (isValid) {
console.log('资源存在,继续加载');
this.checkAndLoadGLB(url, this.mdoel.id)
} else {
console.log('资源不存在');
this.$message.warning('资源不存在,请去相关模块维护!');
}
});
checkAndLoadGLB(url, modelId) {
let self = this
this.isGLBCached(modelId).then(cached => {
if (cached) {
this.getGLBById(modelId).then(data => {
console.log('加载进来了 :>> ');
// 这里可以处理已缓存的 GLB 数据,例如加载模型
});
} else {
console.log('新文件', url, modelId);
self.cacheGLB(modelId, ‘需要存的对象’); // 缓存新文件
}
});
},
更多推荐


所有评论(0)