从 SignalDB 迁移到 RxDB:为 Local-First JavaScript 应用选择可持久化数据库与复制引擎 📅 发布时间:2026/9/20 15:48:33 👁 浏览次数: 数据库NoSQL嵌入式数据库实时数据库【免费下载链接】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 与 SignalDB 都是面向 local-first JavaScript 应用的数据库但两者的定位与成熟度差异明显SignalDB 主打信号signals驱动的轻量内存响应式存储而 RxDB 自 2016 年起将持久化存储、MongoDB 风格查询、多标签协调与后端复制作为一等公民内置。本文以 SignalDB 为对照基线深入拆解 RxDB 的存储引擎、复制协议、冲突处理与响应式查询实现附仓库源码路径与配置参数并给出SignalDB 做 UI 响应层、RxDB 做持久化与同步的混合升级路径帮助你在两者之间做出有依据的技术选型。一、SignalDB 简史信号优先的轻量存储SignalDB 于 2023 年出现并在 2024 年经由 Maximilian Stoiber 与一个小型开源社区持续演进。它面向已经习惯细粒度响应式原语signals的开发者——这类原语被 Solid、Vue 的ref、Preact signals 与 Angular signals 广泛采用。SignalDB 对外暴露一套 MongoDB 风格 APIfind、findOne、insert、updateOne并返回在信号依赖变化时会自动重算的响应式游标reactive cursors。SignalDB 的默认存储是内存页面刷新即清空持久化需要通过适配器localStorage、OPFS、自定义显式接入。同步同样是可插拔的SignalDB 提供 sync manager 接口但期望应用自带传输层、冲突策略与服务端。这种极简设计让包体积很小、API 易于上手但一旦应用需要离线保障、多设备同步或大数据集就会把大量工作推给集成方。二、什么是 RxDBRxDB 是一款自 2016 年持续开发的本地优先local-first、NoSQL JavaScript 数据库可运行于浏览器、Node.js、Electron、React Native、Deno、Bun 与 Capacitor。数据通过可替换的 RxStorage 层持久化查询使用 Mongo 风格 selector 引擎并通过 RxJS 提供观察能力Sync Engine复制协议 提供了经过实战检验的复制协议覆盖 HTTP、WebSocket、GraphQL、CouchDB、Firestore、NATS 及自定义后端。与 SignalDB 把存储、复制当作可选附件不同RxDB 将存储、查询与复制视为一等公民原语。正是这种成熟度成为团队在业务超出小库能力后迁移到 RxDB 的主要原因。三、SignalDB 在生产负载下的瓶颈SignalDB 在它所覆盖的范围内设计良好但以下缺口会在生产环境中逐渐显现默认内存存储数据驻留 RAM页面重载即丢失除非接入持久化适配器大数据集还会与 JS 堆中的其他对象争抢内存。自带同步BYO Syncsync manager 是接口而非协议。pull、push、checkpoint、重试与冲突处理都需要自行实现。一旦出现部分离线写入与重连真实世界的同步远比想象中复杂。存储适配器较少相比 RxDB 覆盖 IndexedDB、OPFS、Dexie、SQLite、Memory、MongoDB、DenoKV、FoundationDB 等的存储矩阵SignalDB 的支持后端列表明显更短。多客户端保证有限SignalDB 未内置多标签协调与 leader election两个打开的标签页若无自行实现就会产生数据漂移。生态较小社区插件、示例与长期 issue 历史都更单薄对需要多年交付的商业应用而言生态深度至关重要。无 schema 驱动的迁移SignalDB 集合在运行时是松散类型RxDB 则强制 JSON Schema 校验并在 schema 变化时执行带版本号的迁移。对比数据截至原文档写作时间 2026-07-30SignalDB 在 GitHub 上约 673 starssignaldb/core近 30 天下载约 6,573 次RxDB 约 23,296 starsrxdb包近 30 天下载约 270,494 次。量级差距反映了长期维护与生产部署规模的差异数据源自原对比文档仅作参考。四、为什么团队选择 RxDB 作为替代4.1 持久化存储与可交换存储引擎RxDB 的所有读写都经过 RxStorage 接口抽象。RxStorageDexie等实现类只需实现createStorageInstance()即可无缝接入数据库实例IndexedDB覆盖主流浏览器。OPFS借助 Origin Private File System 获得高吞吐浏览器写入。Dexie轻量的 IndexedDB 封装。Memory用于测试与临时状态。服务端侧SQLite、MongoDB、DenoKV、FoundationDB 等。从源码看getRxStorageDexie() 接收一个可选的DexieSettings参数并返回RxStorageDexie实例在创建存储实例前还会执行参数校验ensureRxStorageInstanceParamsAreCorrect。一个值得注意的约束是Dexie 不支持非必填索引——若 schema 的indexes中出现了不在required列表里的字段会直接抛出DXE1错误见 rx-storage-dexie.ts。这类底层约束正是换引擎前需要了解的差异点。切换存储引擎通常只是一行代码的改动查询、复制与响应式层完全保持不变。4.2 真正的复制协议而非接口占位RxDB Sync Engine 在协议层面定义了 pull、push、checkpoint 与冲突语义应用无需重新发明轮子。其核心位于 replication-protocol 目录replicateRxStorageInstance()统一调度下游downstream拉取与上游upstream推送两个方向的复制循环并维护 checkpoint 队列、firstSyncDone、processed.down/up、resolvedConflicts等事件流见 src/replication-protocol/index.ts。RxReplicationState对外暴露received$、sent$、error$、canceled$、active$、conflict$等可观察对象以及awaitInitialReplication()、awaitInSync()、awaitDocumentPushed()等状态等待 API见 src/plugins/replication/index.ts。失败请求按retryTime自动重试pull 失败会发出RC_PULL错误、push 失败会发出RC_PUSH错误见 src/plugins/replication/index.ts。push 响应若未返回数组会抛出RC_PUSH_NO_AR错误以帮助排查后端实现问题。插件生态已覆盖 HTTP、WebSocket、GraphQL、CouchDB、Firestore、Supabase、NATS 与 P2P。冲突处理器是按集合显式配置的普通函数完全由你掌控。4.3 MongoDB 风格查询 真正的响应式两个库都提供 Mongo 风格 API。RxDB 在此基础上扩展出 可观察查询observable queriesRxQuery 通过 RxJS 发射结果并附赠面向 React、Vue、Svelte、Solid、Angular signals 的框架适配层。从源码看RxQuery.$是一个惰性初始化的 getter它订阅集合的eventBulks$过滤掉 local documents并在每次变更事件到达时可配置节流liveQueryUpdateThrottleTime重新执行查询并发射结果见 src/rx-query.ts。这意味着包括其他标签页写入与复制更新在内的任何变更都会自动触发查询重算。响应式适配层同样简单直接例如 Vue 适配器把 Observable 订阅映射为shallowRef并在onScopeDispose中自动退订见 src/plugins/reactivity-vue/index.ts。4.4 开箱即用的多标签与冲突解决在三个标签页中打开同一个应用RxDB 自动选举 leader、广播变更、跨标签保持查询同步无需额外代码。自定义冲突处理器在每个复制周期运行决定并发编辑如何合并。机制上leader-election 插件 基于broadcast-channel实现waitForLeadership()返回一个 promise只有当选 leader 的实例才会继续执行复制循环startReplicationOnLeaderShip见 src/plugins/replication/index.ts数据库关闭时会先结束选举再清理广播通道见 src/plugins/leader-election/index.ts。冲突处理则由默认冲突处理器兜底isEqual使用深比较判断两侧是否一致可被自定义实现替换为仅比较updatedAt等字段以获得更好性能resolve默认采用master 优先策略即丢弃本地fork状态、采用远端状态见 src/replication-protocol/default-conflict-handler.ts。4.5 自 2016 年积累的成熟生态RxDB 拥有近十年的版本发布史、付费支持选项以及大规模生产部署。local-first 运动恰恰是围绕 RxDB 这类项目成长起来的因为长期运行的数据层需要这种稳定性。关于客户端数据所有权这一更宏观的趋势可参阅 The Future of Local-First Apps 与 offline-first 指南。五、代码示例创建集合与响应式查询下面是一个完整的 RxDB 起步示例——创建数据库、定义带 JSON Schema 的集合、订阅响应式查询并插入文档触发发射import { createRxDatabase, addRxPlugin } from rxdb; import { getRxStorageDexie } from rxdb/plugins/storage-dexie; const db await createRxDatabase({ name: tasksdb, storage: getRxStorageDexie() // 可替换为 OPFS / Memory / SQLite 等任意 RxStorage }); await db.addCollections({ tasks: { schema: { version: 0, // schema 版本号升级时用于版本化迁移 primaryKey: id, type: object, properties: { id: { type: string, maxLength: 40 }, title: { type: string }, done: { type: boolean }, updatedAt: { type: number } }, required: [id, title, done, updatedAt] } } }); // 响应式查询只要结果集发生变化就发射 // 包括其他标签页的写入与复制更新。 const openTasks$ db.tasks .find({ selector: { done: false } }) .sort({ updatedAt: desc }) .$; openTasks$.subscribe(tasks { console.log(Open tasks:, tasks.length); }); await db.tasks.insert({ id: t1, title: Write SignalDB comparison, done: false, updatedAt: Date.now() });要点提示primaryKey必须是 schema 中的必填字符串字段且带有maxLength如示例中的 40这是 RxDB 对主键的硬性约束。.find()返回 RxQuery 对象.exec()用于一次性读取.$是可观察对象、每次变更时发射源码实现见上文 4.3 节。完整 API 面可查阅 RxCollection 与 RxQuery 文档。六、代码示例HTTP 复制HTTP 复制插件 将 RxDB 集合与任何暴露 pull/push 路由的 REST 端点同步。实际上 RxDB 并不存在单独的 HTTP 插件——正如 replication-http 文档 所述复制原语插件rxdb/plugins/replication足够简单可以直接在其上启动 HTTP 复制import { replicateRxCollection } from rxdb/plugins/replication; const replicationState replicateRxCollection({ collection: db.tasks, replicationIdentifier: tasks-http-replication, // 用于断点续传与识别远端状态来源 pull: { async handler(checkpoint, batchSize) { const url /api/tasks/pull?since${checkpoint?.updatedAt ?? 0} limit${batchSize}; const response await fetch(url); const data await response.json(); return { documents: data.documents, // 需要 { _deleted: boolean } 标记删除 checkpoint: data.checkpoint }; } }, push: { async handler(changeRows) { const response await fetch(/api/tasks/push, { method: POST, body: JSON.stringify(changeRows) }); return await response.json(); // 返回冲突文档列表如有 } }, live: true, retryTime: 5000 }); replicationState.error$.subscribe(err console.error(err));replicateRxCollection的完整选项契约定义在 src/types/plugins/replication.d.ts关键参数如下参数默认值说明replicationIdentifier必填复制标识用于断点续传官方建议把服务端 URL 拼入其中deletedField_deleted标记文档删除的字段名可自定义pull.handler(checkpoint, batchSize)必填拉取远端增量文档返回{ documents, checkpoint }pull.stream$无后端变更流live 复制时用于实时推送如 SSEpull.batchSize100单次拉取文档数少于该数则视为已无更多变更push.handler(changeRows)必填推送本地变更返回冲突文档数组push.batchSize100单次推送的本地变更数livetruefalse时复制运行一次、同步完成后自动取消retryTime5000ms失败请求的重试间隔检测到离线→在线会跳过等待waitForLeadershiptrue多标签场景下等待当前实例成为 leader 后再复制autoStarttrue设为false时需手动调用replicationState.start()同一协议可以扩展到多设备同步、按用户或租户的部分复制partial replication以及设备离线后的可恢复传输。七、混合方案在 RxDB 持久化之上运行 SignalDBlocal-first 社区中逐渐流行一种模式用 SignalDB 做前端响应层把存储与同步委托给 RxDB。SignalDB 暴露了持久化适配器接口因此可以编写一个基于 RxDB 的适配器实现以下三步启动时从 RxCollection 读取文档灌入 SignalDB 集合。将 SignalDB 的写入转发给 RxDB使其落入持久化存储。订阅 RxDB 的变更流把远端更新推回 SignalDB触发信号重新发射。最终效果Vue、Solid、React 组件继续消费 SignalDB 友好的信号 API而 IndexedDB/OPFS 持久化、多标签协调、schema 迁移与后端复制全部由 RxDB 承担。对已经投资 SignalDB、但正在触碰其持久化或同步上限的团队来说这是一个务实的渐进升级路径。八、FAQRxDB 能集成框架信号framework signals吗可以。RxDB 内置一套 reactivity 适配器 API把可观察查询映射为 Vue refs、Angular signals、Solid signals、Svelte stores 与 Preact signals。组件代码通过框架原生原语读取集合底层由 RxDB 驱动更新。以 Vue 为例适配器在订阅 Observable 后将其值写入shallowRef并触发triggerRef同时利用onScopeDispose自动清理订阅见 src/plugins/reactivity-vue/index.ts。SignalDB 可以用 RxDB 持久化吗可以。SignalDB 的持久化接口接受自定义适配器一个基于 RxDB 的适配器把文档存入 RxCollection从而让 SignalDB 获得 IndexedDB、OPFS、SQLite 或任意 RxStorage 上的持久化能力外加完整的 RxDB 复制引擎 用于后端同步。这正是第七节描述的混合架构。两个项目的成熟度如何RxDB 自 2016 年持续开发定期发布版本并已在浏览器、Node.js、Electron、React Native、Deno、Bun 等环境投入生产。SignalDB 始于 2023 年仍在扩展其适配器与同步面。对长期运行的应用而言RxDB 的发布历史与生态是更稳妥的选择。查询语法有何异同两个库都使用 MongoDB 风格 selector。RxDB 的查询返回 RxQuery 对象提供.exec()一次性读取与.$可观察对象任何变更——包括其他标签页与复制——都会触发发射SignalDB 则返回绑定其信号运行时的响应式游标。两者之间的 selector 迁移大多是机械性的。九、对比总表FeatureSignalDBRxDBFirst release20232016Default storageIn memoryDurable via RxStorageStorage adapterslocalStorage, OPFS, customIndexedDB, OPFS, Dexie, Memory, SQLite, MongoDB, DenoKV, FoundationDB, moreQuery APIMongoDB-style, reactive cursorsMongoDB-style, observable queriesReactivityFramework signalsRxJS plus framework adapters for React, Vue, Svelte, Solid, AngularSchema and migrationsLoose typingJSON Schema with versioned migrationsReplicationBring-your-own sync interfaceBuilt-in Sync Engine with HTTP, WebSocket, GraphQL, CouchDB, Firestore, NATS, P2PConflict resolutionApplication-definedPer-collection conflict handlersMulti-tab supportManualBuilt-in leader election and broadcastRuntimesBrowser, Node.jsBrowser, Node.js, Electron, React Native, Deno, Bun, CapacitorEcosystem ageNewDecade of releases and plugins十、选型建议原型、教学或纯内存 UI 状态SignalDB 的信号风格 API 足够轻快接入成本最低。需要持久化、离线优先、多标签一致与后端复制的长期业务应用RxDB 的存储抽象、复制协议与冲突处理是现成的一等公民能力源码复制原语、复制协议与文档均提供了完整可查的实现依据。已深度使用 SignalDB 的团队不必推倒重来采用第七节的混合适配器方案把持久化与同步逐步下沉到 RxDB风险更低。更宏观的视角可参考 The Future of Local-First Apps 与 offline-first 指南理解客户端数据所有权这一趋势如何推动这类选型决策。赞分享数据库NoSQL嵌入式数据库实时数据库【免费下载链接】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 深度解析local-first 响应式 NoSQL 数据库的架构、复制引擎与快速上手RxDB 深度解析local first 响应式 NoSQL 数据库的架构、复制引擎与快速上手 导读 RxDB 是一个面向 JavaScript 应用的 lo数据库NoSQL嵌入式数据库实时数据库React Table Library性能优化5个技巧提升大型表格渲染速度React Table Library性能优化5个技巧提升大型表格渲染速度 React Table Library 是一款轻量级且功能强大的 React 表格数据库NoSQL嵌入式数据库实时数据库RxDB 备选方案全景JavaScript realtime local-first 数据库生态横向对比指南RxDB 备选方案全景JavaScript realtime local first 数据库生态横向对比指南 本文基于 RxDB 官方文档中的 Alterna数据库NoSQL嵌入式数据库实时数据库上一篇netboot.xyz技术架构详解从模板到启动镜像下一篇WinUtil告别繁琐设置一键实现Windows系统优化与软件管理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考