尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RxDB 的 Dexie.js RxStorage 实战指南:基于 IndexedDB 的浏览器存储、Node.js Polyfill 与后端同步方案

RxDB 的 Dexie.js RxStorage 实战指南:基于 IndexedDB 的浏览器存储、Node.js Polyfill 与后端同步方案 RxDB 的 Dexie.js RxStorage 实战指南基于 IndexedDB 的浏览器存储、Node.js Polyfill 与后端同步方案【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdb在浏览器中使用 RxDB 时官方默认推荐使用基于 Dexie.js 与 单元测试 解释其底层原理、局限与取舍。读完本文你将能在浏览器侧项目、单元测试以及需要 Node 环境执行的场景中正确选用与配置该存储并判断何时应切换到官方 Premium IndexedDB RxStorage。Dexie.js RxStorage 是什么RxDB 是一个本地优先local-first数据库核心设计是可插拔的 RxStorage 抽象层同一个数据库 API 可以运行在内存、IndexedDB、SQLite、MongoDB 等不同后端之上。Dexie.js RxStorage 就是这一抽象层在浏览器 IndexedDB 上的实现其导出的工厂函数为getRxStorageDexie()存储名称为dexie见 dexie-helper.ts 中的RX_STORAGE_NAME_DEXIE。官方对它的定位非常明确面向浏览器中的小项目与原型Dexie RxStorage 应作为默认选择见 rx-storage-dexie.md。它的优点是接入成本极低、生态成熟可复用 Dexie.js 庞大的 addon 插件体系缺点是相对官方 Premium IndexedDB RxStorage 在读写性能与构建体积上存在差距。Dexie.js vs IndexedDB Storage何时应该切换虽然 Dexie.js RxStorage 可以免费使用但官方建议大多数专业项目在生产环境中切换到Premium IndexedDB RxStorage原因如下更快且构建体积最多减少 36%Premium 实现绕过了 Dexie 封装层减少了代码量与间接调用。读写性能更好官方有专门的 性能文档 佐证。附件存储为二进制而非 base64可减少约 33% 的占用空间详见 rx-attachment。不使用 Batched Cursor 或自定义索引Dexie 方案在这两点上会拖慢查询相关背景见 slow-indexeddb。支持非必填索引这是 Dexie.js 做不到的见下文“非必填索引限制”一节。类 WAL 写入模式类似 SQLite 的写入方式写入更快、响应性更好。支持 Storage Buckets API可精细管理存储配额见 rx-storage-indexeddb 文档。在阅读后续内容时请牢记这一取舍本文方案适合快速原型与中小型项目追求极致性能与生产级能力时应评估 Premium 方案。快速上手引入 Dexie Storage 并创建数据库Dexie RxStorage 的引入非常直接使用官方rxdb/plugins/core与rxdb/plugins/storage-dexie两个入口import { createRxDatabase } from rxdb/plugins/core; import { getRxStorageDexie } from rxdb/plugins/storage-dexie; const db await createRxDatabase({ name: exampledb, storage: getRxStorageDexie() });在 package.json 中可以看到该插件的包导出配置dist/types/plugins/storage-dexie/index.d.ts类型、dist/cjs与dist/esm两份产物ESM 为默认入口同时兼容 CommonJS 与浏览器打包器。从源码结构看getRxStorageDexie()内部会构造一个RxStorageDexie实例并持有用户传入的DexieSettings见 rx-storage-dexie.ts。每个 RxStorage 实例在创建时都会通过ensureRxStorageInstanceParamsAreCorrect()做参数校验见 rx-storage-dexie.ts。非必填索引限制一个需要特别注意的限制Dexie.js不支持非必填索引。在RxStorageDexie.createStorageInstance()中如果 schema 里声明了索引字段但该字段没有出现在required数组中会直接抛出错误码DXE1见 rx-storage-dexie.ts。对应测试见 rx-storage-dexie.test.ts。因此使用本存储时凡是需要建索引的字段都必须设为必填。在 Node.js 中运行用 fake-indexeddb Polyfill IndexedDBNode.js 本身没有 IndexedDB API因此 Dexie RxStorage 无法直接运行。官方推荐使用 fake-indexeddb 模块进行 Polyfill并把实例传给getRxStorageDexie()import { createRxDatabase } from rxdb/plugins/core; import { getRxStorageDexie } from rxdb/plugins/storage-dexie; // npm install fake-indexeddb --save const fakeIndexedDB require(fake-indexeddb); const fakeIDBKeyRange require(fake-indexeddb/lib/FDBKeyRange); const db await createRxDatabase({ name: exampledb, storage: getRxStorageDexie({ indexedDB: fakeIndexedDB, IDBKeyRange: fakeIDBKeyRange }) });DexieSettings实际上继承了 Dexie 的DexieOptions因此indexedDB与IDBKeyRange等选项会直接传给 Dexie 构造函数类型定义见 types/plugins/dexie.d.ts。这一能力也直接服务于仓库的测试体系fake-indexeddb版本 6.2.5是 devDependency见 package.json单元测试 rx-storage-dexie.test.ts 正是用fake-indexeddb的indexedDB作为测试环境仓库还提供了大量以DEFAULT_STORAGEdexie运行测试的脚本例如test:fast:dexie、test:node:dexie、test:browser:dexie见 package.json。这意味着你可以用同样的方式在自己的 Node.js 单元测试或服务端脚本中完整运行 Dexie RxStorage。使用 Dexie Addons复用 Dexie.js 插件生态Dexie.js 拥有自己的插件体系addons覆盖加密、复制等场景。使用 Dexie RxStorage 时可以把这些插件通过addons选项传入const db await createRxDatabase({ name: exampledb, storage: getRxStorageDexie({ addons: [ /* Your Dexie.js plugins */ ] }) });在源码中addons 同样属于DexieOptions的一部分getDexieDbWithTables()会以new Dexie(dexieDbName, useSettings)创建底层 Dexie 实例useSettings是对用户 settings 的浅拷贝并强制设置autoOpen false见 dexie-helper.ts从而保证数据库的打开时机由 RxStorage 内部控制。还有一个值得关注的设计点由于 IndexedDB 不适合动态建表Dexie RxStorage为每个 RxStorage 实例创建一个独立的 Dexie 数据库命名为rxdb-dexie-databaseName--schema.version--collectionName见 dexie-helper.ts每个库内包含docs、changes、attachments三张表常量定义见 dexie-helper.ts并配合引用计数实现连接复用与正确关闭见 closeDexieDb。这解释了为什么一个 RxDB 数据库中多个 collection 会对应多个底层 IndexedDB 数据库。与后端同步的两种路线本地数据与远端后端保持同步是 RxDB 的核心能力。使用 Dexie RxStorage 时有两种典型路线Dexie Cloud官方托管方案适合快速搭建开箱即用地提供云端后端与冲突解决。RxDB 原生 replication对后端、数据流与 冲突处理 拥有完全控制权。两条路线各有适用场景追求快速起步可选 Dexie Cloud需要自主可控与高可定制性则选 RxDB 原生复制。A. 使用 Dexie Cloud 同步Dexie Cloud是 Dexie 团队提供的官方 SaaS 方案开箱即用地提供自动同步、用户管理与冲突解决自动同步本地 IndexedDB 与云端后端自动保持同步。用户认证内置用户管理认证、角色、权限。冲突解决服务端自动处理冲突。npm install dexie-cloud-addonimport { createRxDatabase } from rxdb/plugins/core; import { getRxStorageDexie } from rxdb/plugins/storage-dexie; import dexieCloud from dexie-cloud-addon; const storage getRxStorageDexie({ addons: [dexieCloud], /* * Whenever a new dexie database instance is created, * this method will be called. */ async onCreate(dexieDatabase, dexieDatabaseName) { await dexieDatabase.cloud.configure({ databaseUrl: https://yourdatabase.dexie.cloud, requireAuth: true // optional }); } }); const db await createRxDatabase({ name: mydb, storage });注意onCreate回调正是DexieSettings中额外扩展的字段见 types/plugins/dexie.d.ts其执行时机在new Dexie(...)之后、dexieDb.version(1).stores(...)建表之前见 dexie-helper.ts因此非常适合做 Dexie 级配置如 Cloud 初始化、addon 配置。B. 使用 RxDB 原生复制如果需要最大灵活性可以选择 RxDB 众多复制插件之一CouchDB 复制与 CouchDB 服务器同步。GraphQL 复制对接任意 GraphQL 端点适合自定义 schema 或需要 GraphQL 查询能力时。基于 REST API 的自定义复制通过 pull/push handler 对接任意 RESTful 后端。下面以 CouchDB 为例展示完整链路创建数据库 → 添加 collection → 启动复制。import { replicateCouchDB } from rxdb/plugins/replication-couchdb; import { getRxStorageDexie } from rxdb/plugins/storage-dexie; import { createRxDatabase } from rxdb/plugins/core; const db await createRxDatabase({ name: mydb, storage: getRxStorageDexie() }); await db.addCollections({ humans: { schema: { version: 0, type: object, primaryKey: id, properties: { id: { type: string, maxLength: 100 }, name: { type: string }, age: { type: number } }, required: [id, name] } } }); const replicationState replicateCouchDB({ replicationIdentifier: my-couchdb-replication, collection: db.humans, // The URL to your CouchDB endpoint url: http://example.com/db/humans });仓库在 test/replication-couchdb.test.ts 中正是以DEFAULT_STORAGEdexie运行 CouchDB 复制测试见 package.json说明该组合是经过完整测试验证的成熟路径。liveQuery 与 RxDB 的响应式查询Dexie.js 提供liveQuery特性可在数据变化时自动刷新查询结果。但 RxDB 本身内置 响应式查询通常无需启用 Dexie 的 liveQuerycollection.find().$.subscribe(results { /* ... 每当结果变化时自动触发 ... */ });RxDB 会监听变更并自动推送新结果UI 无需额外插件或手动轮询即可保持同步。这一机制在底层由 Dexie RxStorage 的changeStream()返回changes$Subject 的可观察流驱动写入完成后会发出带 checkpoint 的变更事件见 rx-storage-instance-dexie.ts 与 bulkWrite 中的事件发布。底层实现要点查询、布尔索引与附件存储Mango 查询如何在 Dexie 上执行Dexie RxStorage 的查询逻辑位于 dexie-query.ts它会根据查询计划queryPlan把 RxDB 的 Mango 查询转换成 IndexedDB 的IDBKeyRange见 getKeyRangeByQueryPlan然后通过底层 IndexedDB 事务打开复合索引游标逐条读取如果查询条件未被索引完全满足还会用getQueryMatcher()在内存中过滤如果排序未被索引满足则用getSortComparator()在内存中排序见 dexieQuery。游标在queryPlan.sortSatisfiedByIndex且已收集够skip limit条时提前终止避免全表扫描。count()则优先走索引的index.count(keyRange)快速路径见 dexieCount。布尔索引与 key-compression 字段转义IndexedDB 不支持布尔类型索引因此 Dexie RxStorage 会把布尔值写为字符串1/0存储查询范围时再映射回来见 dexie-helper.ts 的 fromStorageToDexie/fromDexieToStorage 与 dexie-query.ts 的 rangeFieldToBooleanSubstitute。另外若启用了 key-compression 插件字段名可能以管道符|开头而 IndexedDB 不允许这类键名因此写入时会把|替换为__DEXIE_PIPE_SUBSTITUTE读回时再还原见 dexie-helper.ts。以上两套转换均有对应单元测试覆盖见 rx-storage-dexie.test.ts。Store Schema 的自动生成Dexie 的 store schema 字符串由getDexieStoreSchema()生成见 dexie-helper.ts主键排第一位随后是_deletedprimaryKey复合索引、用户声明的索引、以及_meta.lwtprimaryKey支撑getChangedDocumentsSince与_meta.lwt支撑 cleanup等内部索引最终转换为 Dexie 的[field1field2]复合索引语法。附件存储附件的二进制数据存放在独立的attachments表中以documentId || attachmentId为键见 attachmentObjectId写入与删除在bulkWrite的同一个 Dexie 事务中完成见 rx-storage-instance-dexie.ts读取走getAttachmentData()见 rx-storage-instance-dexie.ts。这也是前文提到 Premium 方案能以二进制替代 base64 从而节省约 33% 空间的原因之一。关闭非 Premium 控制台日志Dexie RxStorage 是免费的开源实现首次写入时会在控制台输出一条提示信息告知社区存在更快的 Premium 存储方案。该日志在 bulkWrite 中只输出一次shownNonPremiumLog标志控制并且会先检查hasPremiumFlag()。如果你已购买 Premium 并希望关闭该日志可以调用import { setPremiumFlag } from rxdb-premium/plugins/shared; setPremiumFlag();性能对比Dexie.js RxStorage 的性能足以应对大多数场景但其他存储方案如内存存储、Premium IndexedDB在特定操作上可能明显更优。下图是官方在 Chrome 浏览器环境对各 RxStorage 的基准对比纵轴为毫秒越低越好可直观看到 Dexie.js 在批量插入等操作上与内存型/IndexedDB 方案的差距从图表可以观察到memory与IndexedDB-memory-mapped在多数操作中耗时极低dexie.js在Bulk insert 500 docs等批量操作中表现尚可但相比 Premium IndexedDB 方案在读取、并行查询等操作上仍有差距。这正是官方建议生产环境评估 Premium IndexedDB RxStorage 的原因。仓库还提供了性能基准脚本test:performance:dexie见 package.json可自行在目标环境复测。FAQDexie.js 是什么相比原生 IndexedDB 有什么优势Dexie.js 是专为解决原生 IndexedDB 复杂回调式 API 而设计的极简 Promise 封装。它提供直观可链式调用的查询 API、更简单的数据库 schema 定义方式以及非常健壮的事务管理。但 Dexie 缺少文档型 NoSQL 数据库的高级查询能力如深层嵌套 JSON 查询、完整的 MongoDB 风格 selector。而 RxDB 把 Dexie 作为底层存储引擎使用弥补了这些不足RxDB 提供完全响应式的高级 NoSQL 查询引擎、跨平台离线复制协议以及 Dexie 本身不具备的内置字段加密能力。总结Dexie.js RxStorage 是浏览器端接入 RxDB 最便捷的存储方案一条工厂函数即可建库天然支持响应式查询、附件与复制协议可通过fake-indexeddb在 Node.js 中运行测试还能复用 Dexie addon 生态包括 Dexie Cloud。理解它的底层实现——每实例一库的表结构、布尔索引与 key-compression 转义、基于查询计划的 IndexedDB 游标扫描——有助于你在真实项目中预判行为与排查问题。同时务必记住两个关键边界索引字段必须为必填且在小项目与原型之外生产环境应评估官方 Premium IndexedDB RxStorage 以获得更好的性能与更小的体积。【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表