ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

IndexedDB 本地数据库

IndexedDB 本地数据库 5.4 IndexedDB 本地数据库IndexedDB 是浏览器原生提供的事务型结构化本地数据库专为解决 Web Storage 容量上限低、仅支持字符串存储、查询能力弱的问题。它支持大容量存储、索引查询、事务处理能够存储海量结构化业务数据与二进制资源是复杂离线应用、大数据本地缓存的核心存储方案。5.4.1 核心概念与基础操作一、核心特性大容量存储单域名存储上限通常在 50MB ~ 数百MB 级别远高于 Web Storage 的 5MB支持存储文件、二进制大对象。结构化存储以键值对形式存储 JavaScript 对象、数组、二进制数据等无需手动序列化支持嵌套数据结构。异步非阻塞所有操作均为异步事件驱动基于回调执行不会阻塞主线程避免大数据量操作导致页面卡顿。事务型保证所有数据操作都在事务中执行具备原子性、一致性操作失败自动回滚保证数据完整性。索引与查询支持创建多字段索引通过索引实现高效条件查询支持游标遍历与范围筛选。同源隔离严格遵循同源策略不同站点无法访问对方的数据库保障数据安全。二、核心概念IndexedDB 概念类比关系型数据库含义说明Database数据库数据库实例独立的存储单元通过名称唯一标识支持多版本管理Object Store对象仓库数据表数据存储的集合存储键值对记录每个仓库对应一类业务数据Index索引索引基于对象仓库的字段创建用于加速条件查询支持唯一约束Transaction事务事务数据操作的执行单元所有读写都必须在事务中进行分为只读/读写两种模式Cursor游标遍历指针用于逐条遍历对象仓库或索引中的数据支持范围筛选与增量读取三、基础操作语法1. 打开/创建数据库通过indexedDB.open(dbName, version)打开数据库若数据库不存在则自动创建版本号提升时触发升级事件。 数据库结构的修改创建仓库、创建索引只能在upgradeneeded事件中执行这是 IndexedDB 版本管理的核心机制。// 打开名为 UserDB 的数据库版本号为 1 const request indexedDB.open(UserDB, 1); let db null; // 数据库升级时触发首次创建、版本号提升 request.onupgradeneeded function(e) { db e.target.result; // 创建对象仓库相当于表指定主键为 id const userStore db.createObjectStore(users, { keyPath: id }); // 创建索引按用户名查询唯一索引 userStore.createIndex(name, name, { unique: true }); // 创建索引按年龄查询非唯一索引 userStore.createIndex(age, age, { unique: false }); }; // 数据库打开成功 request.onsuccess function(e) { db e.target.result; console.log(数据库初始化完成); }; // 数据库打开失败 request.onerror function(e) { console.error(数据库打开失败, e.target.error.message); };2. 新增数据使用readwrite模式的事务add()方法用于纯新增主键重复会抛出错误put()方法为「新增或覆盖更新」主键存在则更新、不存在则新增。function addUser(user) { // 创建读写事务指定操作的仓库 const transaction db.transaction([users], readwrite); // 获取对象仓库实例 const store transaction.objectStore(users); // 执行新增操作 const request store.add(user); request.onsuccess () console.log(用户新增成功); request.onerror () console.error(用户新增失败); } // 调用示例 addUser({ id: 1, name: zhangsan, age: 25, city: beijing });3. 查询数据主键查询get(key) 按主键获取单条数据全量查询getAll() 获取仓库中所有数据索引查询通过索引对象按指定字段快速查询// 1. 按主键查询单条数据 function getUserById(id) { const transaction db.transaction([users], readonly); const store transaction.objectStore(users); const request store.get(id); request.onsuccess () { console.log(查询结果, request.result); }; } // 2. 按索引查询 function getUserByName(name) { const transaction db.transaction([users], readonly); const store transaction.objectStore(users); const nameIndex store.index(name); // 获取索引对象 const request nameIndex.get(name); request.onsuccess () { console.log(按名称查询结果, request.result); }; }4. 更新与删除// 更新数据put 方法主键存在则覆盖更新 function updateUser(user) { const transaction db.transaction([users], readwrite); const store transaction.objectStore(users); store.put(user); } // 按主键删除单条数据 function deleteUser(id) { const transaction db.transaction([users], readwrite); const store transaction.objectStore(users); store.delete(id); } // 清空仓库所有数据 function clearAllUsers() { const transaction db.transaction([users], readwrite); const store transaction.objectStore(users); store.clear(); }5. 游标遍历适合大批量数据遍历、范围查询场景避免一次性加载全部数据到内存支持增量处理。function traverseAllUsers() { const transaction db.transaction([users], readonly); const store transaction.objectStore(users); const request store.openCursor(); // 打开游标 request.onsuccess function(e) { const cursor e.target.result; if (cursor) { console.log(当前记录, cursor.value); cursor.continue(); // 移动到下一条 } else { console.log(遍历完成); } }; }5.4.2 常用封装思路原生 IndexedDB API 基于事件回调写法繁琐、容易形成回调地狱且版本管理、错误处理分散。实际项目中通常会进行分层封装简化调用方式统一管理底层逻辑。一、封装核心目标回调 Promise 化将事件回调转为 Promise支持 async/await 语法大幅提升代码可读性与可维护性。接口简化屏蔽事务、请求对象等底层概念对外提供简洁的增删改查业务方法。统一管理集中处理数据库打开、版本升级、错误捕获、事务生命周期管理。二、基础 Promise 封装最轻量化的封装将单次操作包装为 Promise适合简单业务场景快速接入。// 封装打开数据库 function openDB(dbName, version, onUpgrade) { return new Promise((resolve, reject) { const request indexedDB.open(dbName, version); request.onupgradeneeded e onUpgrade(e.target.result); request.onsuccess e resolve(e.target.result); request.onerror e reject(e.target.error); }); } // 封装新增操作 function addItem(db, storeName, data) { return new Promise((resolve, reject) { const transaction db.transaction([storeName], readwrite); const store transaction.objectStore(storeName); const request store.add(data); request.onsuccess () resolve(request.result); request.onerror () reject(request.error); }); } // 使用示例 async function demo() { const db await openDB(DemoDB, 1, (db) { // 升级回调中创建仓库 db.createObjectStore(items, { keyPath: id }); }); await addItem(db, items, { id: 1, title: 测试数据 }); }三、类式封装将数据库操作封装为独立工具类统一管理数据库实例、配置与生命周期是中型项目的主流方案。class IndexedDBHelper { constructor(dbName, version, storesConfig) { this.dbName dbName; this.version version; this.storesConfig storesConfig; // 仓库配置名称、主键、索引 this.db null; } // 初始化数据库 init() { return new Promise((resolve, reject) { const request indexedDB.open(this.dbName, this.version); request.onupgradeneeded (e) { const db e.target.result; // 批量创建对象仓库与索引 this.storesConfig.forEach(config { if (!db.objectStoreNames.contains(config.name)) { const store db.createObjectStore(config.name, { keyPath: config.keyPath }); config.indexes?.forEach(idx { store.createIndex(idx.name, idx.field, { unique: idx.unique || false }); }); } }); }; request.onsuccess (e) { this.db e.target.result; resolve(this); }; request.onerror (e) reject(e.target.error); }); } // 新增数据 add(storeName, data) { return this._execute(storeName, readwrite, store store.add(data)); } // 按主键查询 get(storeName, key) { return this._execute(storeName, readonly, store store.get(key)); } // 通用事务执行方法统一封装 Promise _execute(storeName, mode, handler) { return new Promise((resolve, reject) { const transaction this.db.transaction([storeName], mode); const store transaction.objectStore(storeName); const request handler(store); request.onsuccess () resolve(request.result); request.onerror () reject(request.error); }); } } // 使用示例 const db new IndexedDBHelper(AppDB, 1, [ { name: users, keyPath: id, indexes: [{ name: name, field: name, unique: true }] } ]); db.init().then(async () { await db.add(users, { id: 1, name: lisi, age: 30 }); const user await db.get(users, 1); });四、开源库方案复杂项目推荐使用成熟的开源封装库避免重复造轮子Dexie.js最主流的 IndexedDB 封装库提供类似 MongoDB 的链式查询 API完整支持事务、索引、范围查询功能完善生态成熟。localForageAPI 风格与 Web Storage 高度一致简单易用自动降级适配 Web Storage、IndexedDB 等多种存储引擎适合简单的键值存储场景。五、适用场景与边界适用场景海量结构化业务数据存储、离线应用数据持久化、大文件/二进制数据本地缓存、复杂条件查询场景。不适用场景少量简单配置数据优先使用 localStorage强实时性的高频读写场景需注意异步开销。
返回列表