ARTICLE DETAIL

资讯详情

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

RxDB 作为 InstantDB 替代方案:自建后端、开源与真正的离线本地数据库

RxDB 作为 InstantDB 替代方案:自建后端、开源与真正的离线本地数据库 数据库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点击查看免费下载如果你正在寻找InstantDB 的替代方案大概率是出于以下三个诉求之一需要一个真正的 offline-first 本地数据库而非只是网络缓存希望把任意自建后端接入同步层而非绑定托管的 Datalog 服务以及需要一个可以审计、fork、自托管的开源技术栈而非依赖单一厂商。RxDBReactive Database正是一个客户端 NoSQL 数据库数据存储在浏览器、移动端运行时、Electron 或 Node.js 本地并通过可插拔的复制引擎与任何你掌控的后端同步。它完全开源并已在离线优先的生产应用中使用多年。本文将以 RxDB 为主线对比 InstantDB 的托管模式与查询模型并深入仓库源码说明如何用 RxDB 构建自带后端Bring Your Own Backend的实时、离线优先应用。InstantDB 速览它解决什么问题InstantDB 于 2023 年从 Y Combinator 孵化目标是把实时、协作应用的开发体验做得像写静态页面一样简单。其产品核心是一个用 Clojure 编写的托管同步服务向 JavaScript 客户端暴露 Datalog 风格的查询语言。客户端通过乐观更新写入服务端保存权威状态变更再实时流回每一个已连接的设备。这一设计非常适合原型和小型协作工具掌握 Datalog 之后查询表达力很强SDK 也自动处理订阅与回滚。代价是同步引擎与存储深度绑定 InstantDB 云服务而客户端本地层本质上是查询缓存而非完整的数据库。RxDB 是什么三条核心设计RxDB 是一个可嵌入的 JavaScript 数据库围绕三个核心理念构建本地优先存储Local-first storage每次读写都首先命中本地引擎网络断开时应用照常工作。参见 offline-first 与 local-first future。响应式查询Reactive queries任何 RxQuery 都返回一个可观察对象Observable当匹配数据发生变化时无论是本地写入、其他标签页还是远端推送都会重新发出新结果。参见 reactivity。可插拔复制Pluggable replicationSync Engine 可以对接任意 HTTP 端点、GraphQL 服务、CouchDB、Firestore或通过 WebRTC 直连对端。复制协议有完整文档你可以在任何后端上实现它例如基于 HTTP replication。存储同样是可插拔的同一个集合可以在 IndexedDB、OPFS、SQLite、内存或 LocalStorage 上运行而无需修改任何应用代码。InstantDB 的五个局限性InstantDB 适合很多应用但以下几类约束会促使团队寻找替代方案。1. 同步服务仅限托管InstantDB 强制使用其托管后端没有可用于生产环境的开源服务端。如果你的应用必须运行在客户硬件、受监管环境或 InstantDB 云未覆盖的地区就会陷入困境。2. Datalog 有学习曲线InstantDB 使用 Datalog 风格的三元组语法。这一模型一旦掌握确实表达力强但新贡献者在写出第一个功能之前必须先学习它。RxDB 采用 JSON Mango 查询格式任何接触过 MongoDB、PouchDB 或 Supabase 的开发者都会感到熟悉。3. 本地层只是缓存InstantDB 在客户端缓存已订阅查询的结果以保证短时网络中断下 UI 仍可响应。但它不是一个完整的本地数据库你不能运行从未订阅过的任意查询缓存也可能被逐出。RxDB 则将每个被复制集合的每个文档都持久化到磁盘并允许你在任何时间查询任意字段。4. 存储适配器选项少InstantDB 客户端自己决定持久化层。RxDB 则暴露了一个 storage interface提供 IndexedDB、OPFS、SQLite、Memory、LocalStorage、Dexie 等适配器你可以按平台或按集合切换存储。5. 冲突解决的旋钮有限InstantDB 在内部解决写冲突你获得乐观更新和回滚但解决策略基本固定。RxDB 允许你为每个集合编写 自定义冲突处理器或在需要无服务端仲裁的自动合并时选择 CRDT。两个项目都在积极开发中。根据 InstantDB 替代方案文档 的记录截至 2026 年 7 月 30 日InstantDB 拥有 10,366 个 GitHub Star而 RxDB 拥有 23,296 个。为什么团队会选择 RxDB自带后端Bring Your Own BackendRxDB 不强制依赖任何云服务。你可以把一个集合连接到任何你已经在运行的后端基于 HTTP replication 的 REST API带订阅的 GraphQL 端点使用官方复制插件的 CouchDB 或 Firestore 实例用于设备直连同步的 WebRTC 对端。同步协议本质上是一个pull push 事件流三段式契约。任何能实现这三个调用的服务都能成为 RxDB 的后端。完全开源RxDB 的核心与存储适配器采用 Apache 2.0 许可。你可以阅读引擎的每一行代码、fork 它并在不向第三方发送数据的前提下运行。JSON Mango 查询查询写法与 JavaScript 生态保持一致。完整的操作符列表参见 RxQuery。开箱即用的可观察查询每个查询都是一个 RxJS 可观察对象。UI 框架只需订阅一次数据变化时自动重新渲染。参见 reactivity 与 optimistic UI。真正的冲突解决可以为每个集合接入 自定义冲突处理器或在希望无需手写合并逻辑即可获得可交换合并时启用 CRDT。多存储与多标签页同一份代码可以在浏览器的 IndexedDB、高写入吞吐的 OPFS、React Native 上的 SQLite 或测试用的内存存储上运行。multi-tab 层通过共享 Worker 或 BroadcastChannel 保证两个浏览器标签页看到相同的状态。代码示例把 InstantDB 查询改写为 RxDB一个典型的 InstantDB 查询——获取某用户的未完成 todo——大致如下// InstantDB const { data } db.useQuery({ todos: { $: { where: { ownerId: userId, done: false } } } });同样的查询在 RxDB 中使用 Mango 查询格式并返回一个可观察对象// RxDB const query db.todos.find({ selector: { ownerId: userId, done: false }, sort: [{ createdAt: desc }] }); const todos$ query.$; // ObservableRxDocument[]todos$会在匹配文档被插入、更新或删除时重新发出数据无论该变化来自本地写入、另一个标签页还是复制流。RxDB 的 RxQuery 还提供findOne()返回单个 RxDocument 或 null、count()等查询类型并通过query.exec()获取一次性的结果集。$是一个BehaviorSubject订阅时会立刻发出当前结果之后每次数据库变化都会再次触发——这正是UI 始终与数据库状态一致的实现基础。参见 rx-query.md。代码示例用可观察查询驱动 React UI下面是一个小型 React 组件复刻了 InstantDB 订阅查询 乐观写入的使用模式import { useEffect, useState } from react; import { db } from ./db; export function TodoList({ userId }: { userId: string }) { const [todos, setTodos] useStateany[]([]); useEffect(() { const sub db.todos .find({ selector: { ownerId: userId, done: false } }) .$.subscribe(setTodos); return () sub.unsubscribe(); }, [userId]); async function addTodo(title: string) { // Optimistic write: the local store updates first, // replication pushes it to the backend in the background. await db.todos.insert({ id: crypto.randomUUID(), ownerId: userId, title, done: false, createdAt: new Date().toISOString() }); } return ( ul {todos.map(t li key{t.id}{t.title}/li)} button onClick{() addTodo(New task)}Add/button /ul ); }本地insert立即完成。复制层在网络可用时把写入流式推送到服务端任何冲突都会经过配置的冲突处理器。完整的乐观 UI 模式参见 optimistic-ui.md。深入RxDB 复制引擎的工作方式要理解RxDB 为什么能对接任意后端需要看复制协议本身。核心文档 replication.md 与源码 src/plugins/replication/index.ts 表明复制引擎刻意把复杂部分放在 RxDB 客户端易于理解复制像 git 一样工作开发者只需理解三个简单端点复杂逻辑在 RxDB 侧冲突处理、离线-在线切换都在 RxDB 内部实现后端可以很笨因此协议几乎兼容任何后端为客户端设备优化性能文档按批次分组传输JSON.parse()整块数据比逐行解析更快IndexedDB/OPFS 的批量写入也更快离线优先支持客户端侧内置冲突处理断网期间的修改在重连后无缝同步多标签页支持多个浏览器标签页中同一时刻只有一个运行复制节省客户端与后端资源。文档层git 式合并在 RxDocument 层面复制过程如下A---B-----------D master/server state \ / B---C---D fork/client state客户端从 master 拉取最新状态B客户端做出若干修改C D客户端把自己已知的最新 master 状态B和文档的新状态D一起推送给 master若 master 状态与客户端假设的最新 master 状态B一致则新状态D成为最新 master 状态若 master 也有变更则产生冲突必须在客户端解决。传输层三个必须实现的方法所有处理器都按文档批次工作服务端只需实现三个方法即可兼容复制pullHandler输入最后一个 checkpoint或 null返回所有在该 checkpoint之后写入的文档以及最后返回文档的 checkpointpushHandler客户端把每次写入的assumedMasterState假设的 master 状态与newForkState新的 fork 状态数组发送给 master返回所有冲突的 master 文档状态无冲突时返回空数组pullStream一个可观察对象持续发出 master 的写入批次及最新 checkpoint。-------- -------- | | pullHandler() | | | |--------------------- | | | | | | | | | | | Client | pushHandler() | Server | | |--------------------- | | | | | | | | pullStream$ | | | | -------------------------| | -------- --------复制运行在两种模式中Checkpoint 迭代模式首次复制或客户端重新上线时用 checkpoint 追赶服务端状态。checkpoint 是最后拉取文档的部分字段子集。例如文档含id和updatedAt字段两者即可组成 checkpoint。当后端返回空数组没有更新文档时自动切换到事件观察模式。事件观察模式连接期间通过pullStream$观察后端事件并持久化到客户端。若后端无法提供完整事件流也可以只发出RESYNC事件让 RxDB 回到 checkpoint 迭代模式追赶。客户端断线重连时pullStream$也应发出RESYNC以补齐错过的服务端事件。服务端数据布局约束使用复制前需保证两点文档可按最后写入时间确定性排序即使两个文档最后写入时间相同也有可预测的排序顺序最常用的做法是把primaryKey作为第二排序参数加入 checkpoint文档永不物理删除而是把_deleted置为true删除状态必须在数据库中保留才能复制到其他实例。若后端使用不同字段标记删除可在 push/pull 处理器或 modifier 中转换数据。典型文档形如const docData { id: foobar, name: Alice, lastName: Wilson, /** * Contains the last write timestamp * so all document writes can be sorted by that value * when they are fetched from the remote instance. */ updatedAt: 1564483474, /** * Instead of physically deleting documents, * a deleted document gets replicated. */ _deleted: false }默认删除标记字段是_deleted若远程端点使用其他字段名可在复制选项中设置deletedFieldRxDB 会在所有 pull/push 请求上自动映射。replicateRxCollection() 与主要参数通过replicateRxCollection()启动单个 RxCollection 的复制来源replication.mdimport { replicateRxCollection } from rxdb/plugins/replication; import { lastOfArray } from rxdb; const replicationState await replicateRxCollection({ collection: myRxCollection, /** * 复制标识符用于应用重载后恢复复制。 * 与远程服务器复制时建议把服务器 URL 放入其中。 */ replicationIdentifier: my-rest-replication-to-https://example.com/api/sync, /** * 默认进行持续的实时复制。 * 设为 false 时复制只运行一次本地与远端同步后自动取消。 * (可选)默认 true。 */ live: true, /** * 后端请求失败后的重试间隔毫秒。 * 检测到离线-在线切换时会跳过该等待时间。 * (可选)默认 5 秒。 */ retryTime: 5 * 1000, /** * 多实例场景如多个浏览器标签页下复制应只在其中一个标签页运行。 * waitForLeadership: true 会等待当前实例成为 leader。 * [默认 true] */ waitForLeadership: true, /** * 设为 false 时复制不会自动开始 * 而是等待 replicationState.start() 被调用。 * (可选)默认 true */ autoStart: true, /** * 自定义删除字段。若后端使用不同于 _deleted 的字段名 * 在此设置字段名。RxDB 内部仍以 _deleted 存储 * 该设置只在数据层映射字段。 * 若自定义删除字段包含非布尔值则以真值判断删除状态 * 因此也可以使用 deletedAt 时间戳代替布尔值。 * [默认 _deleted] */ deletedField: deleted, /** * 可选仅当你需要把本地变更复制到远程实例时需要。 */ push: { async handler(docs) { const rawResponse await fetch(https://example.com/api/sync/push, { method: POST, headers: { Accept: application/json, Content-Type: application/json }, body: JSON.stringify({ docs }) }); // 包含本次推送出现的所有冲突无冲突时返回空数组 const response await rawResponse.json(); return response; }, /** 一次传给 push handler 的文档数量(可选) */ batchSize: 5, /** 推送前修改所有文档(可选)。返回 null 时跳过该文档 */ modifier: d d, /** * 本地写入发生后通常立即开始推送。 * 提供该函数返回 Promise 时复制会等待其 resolve * 再开始下一轮上游持久化 * 可用于把多次快速写入合并为一次 push 调用。 * (可选) */ waitBeforePersist: () new Promise(resolve requestIdleCallback(resolve)) }, /** * 可选仅当你需要把远程变更复制到本地状态时需要。 */ pull: { async handler(lastCheckpoint, batchSize) { const minTimestamp lastCheckpoint ? lastCheckpoint.updatedAt : 0; const response await fetch( https://example.com/api/sync/ ?minUpdatedAt${minTimestamp} limit${batchSize} ); const documentsFromRemote await response.json(); return { documents: documentsFromRemote, /** * 若 documentsFromRemote.length batchSize * RxDB 认为后端没有更多未复制文档 * 复制会切换到 Event observation 模式。 */ checkpoint: documentsFromRemote.length 0 ? lastCheckpoint : { id: lastOfArray(documentsFromRemote).id, updatedAt: lastOfArray(documentsFromRemote).updatedAt } }; }, batchSize: 10, modifier: d d, /** 后端写入流仅 livetrue 时需要 stream$ */ stream$: pullStream$.asObservable() }, });实时复制的事件流可以用 WebSocket 实现也可以使用长轮询或 Server-Sent Events。后端每次重连都要发出RESYNC让客户端回到 checkpoint 迭代模式补齐遗漏事件const pullStream$ new SubjectRxReplicationPullStreamItemany, any(); let firstOpen true; function connectSocket() { const socket new WebSocket(wss://example.com/api/sync/stream); // event.data 形如 { documents: [...], checkpoint: {...} } socket.onmessage event pullStream$.next(event.data); socket.onclose () connectSocket(); socket.onerror () socket.close(); socket.onopen () { if (firstOpen) { firstOpen false; } else { pullStream$.next(RESYNC); } } }复制状态的观察与管理replicateRxCollection()返回RxReplicationState提供多个可观察属性来源replication.mdmyRxReplicationState.received$.subscribe(doc console.dir(doc)); // 从远程收到的文档 myRxReplicationState.sent$.subscribe(doc console.dir(doc)); // 发往远程的文档 myRxReplicationState.error$.subscribe(error console.dir(error)); // push/pull 错误 myRxReplicationState.canceled$.subscribe(bool console.dir(bool)); myRxReplicationState.active$.subscribe(bool console.dir(bool)); myRxReplicationState.conflict$.subscribe(conflict console.dir(conflict));另有awaitInitialReplication()、awaitInSync()、awaitDocumentPushed()等待特定文档被推送至服务端适合金融交易等敏感写入、reSync()触发 RESYNC 周期、cancel()、pause()/start()、remove()删除复制元数据以重新开始等方法。需要注意的是不应用awaitInitialReplication()/awaitInSync()阻塞整个应用启动——设备离线时这些 Promise 永远不会 resolve正确的做法是把最近一次同步时间存入 local document 并在所有实例上观察它。深入HTTP 复制实战Express MongoDBRxDB 并没有专门的 HTTP 复制插件因为 replication primitives 插件 已足够简单可以直接在其上构建 HTTP 复制完整教程见 replication-http.md。客户端只需要replicateRxCollection// client.ts import { replicateRxCollection } from rxdb/plugins/replication; const replicationState await replicateRxCollection({ collection: myRxCollection, replicationIdentifier: my-http-replication, push: { /* add settings from below */ }, pull: { /* add settings from below */ } });服务端用 Express MongoDB 实现三个端点Pull 端点——按 checkpointupdatedAtid返回后续写入的文档// server.ts import { lastOfArray } from rxdb/plugins/core; app.get(/pull, async (req, res) { const id req.query.id; const updatedAt parseFloat(req.query.updatedAt); const documents await mongoCollection.find({ $or: [ // 必须同时比较 updatedAt 与 id // 因为 updatedAt 不唯一同值时可用 id 排序 { updatedAt: { $gt: updatedAt } }, { updatedAt: { $eq: updatedAt }, id: { $gt: id } } ] }) .sort({updatedAt: 1, id: 1}) .limit(parseInt(req.query.batchSize, 10)).toArray(); const newCheckpoint documents.length 0 ? { id, updatedAt } : { id: lastOfArray(documents).id, updatedAt: lastOfArray(documents).updatedAt }; res.setHeader(Content-Type, application/json); res.end(JSON.stringify({ documents, checkpoint: newCheckpoint })); });Push 端点——接收 changeRows对每一行校验assumedMasterState是否与真实 master 状态一致一致则写入并广播事件不一致则把真实 master 状态放进冲突数组返回// server.ts let lastEventId 0; const pullStream$ new Subject(); app.get(/push, async (req, res) { const changeRows req.body; const conflicts []; const event { id: lastEventId, documents: [], checkpoint: null }; for(const changeRow of changeRows){ const realMasterState await mongoCollection.findOne( {id: changeRow.newDocumentState.id} ); if( realMasterState !changeRow.assumedMasterState || ( realMasterState changeRow.assumedMasterState // 为简单起见这里只比较 updatedAt 值来检测冲突 realMasterState.updatedAt ! changeRow.assumedMasterState.updatedAt ) ) { conflicts.push(realMasterState); } else { await mongoCollection.updateOne( {id: changeRow.newDocumentState.id}, changeRow.newDocumentState ); event.documents.push(changeRow.newDocumentState); event.checkpoint { id: changeRow.newDocumentState.id, updatedAt: changeRow.newDocumentState.updatedAt }; } } if(event.documents.length 0){ pullStream$.next(event); } res.setHeader(Content-Type, application/json); res.end(JSON.stringify(conflicts)); });pullStream 端点——用 Server-Sent EventsSSE把后端持续事件推给客户端实现实时复制// server.ts app.get(/pullStream, (req, res) { res.writeHead(200, { Content-Type: text/event-stream, Connection: keep-alive, Cache-Control: no-cache }); const subscription pullStream$.subscribe(event { res.write(data: JSON.stringify(event) \n\n); }); req.on(close, () subscription.unsubscribe()); });客户端用EventSource连接该端点并喂给pull.stream$连接出错时发出RESYNC让复制回到 checkpoint 迭代模式补齐漏掉的变更// client.ts const myPullStream$ new Subject(); const eventSource new EventSource(http://localhost/pullStream, { withCredentials: true }); eventSource.onmessage event { const eventData JSON.parse(event.data); myPullStream$.next({ documents: eventData.documents, checkpoint: eventData.checkpoint }); }; eventSource.onerror () myPullStream$.next(RESYNC);即使后端无法推送完整文档批次也可以把所有事件映射为RESYNC标志——复制仍能工作只是性能略有下降。生产实现还需补充认证头、为触发变更的客户端跳过其自身的 stream 事件、在端点 URL 中加入版本号并对旧客户端返回426 Upgrade Required参见 replication.md 中基于error$强制刷新页面的示例。冲突处理从默认处理器到 CRDT当多个客户端或服务端同时修改同一文档时复制期间可能产生冲突A---B1---C1---X master/server state \ / B1---C2 fork/client state客户端调用pushHandler()希望把文档从B1推进到C2但实际 master 状态是C1于是 master 拒绝写入并把真实状态C1返回。RxDB 在客户端解决所有冲突调用该 RxCollection 的冲突处理器生成新状态D后再次写入 master。默认冲突处理器总是丢弃 fork 状态、采用 master 状态确保长时间离线的客户端不会在重新上线时意外覆盖他人更改。其实现见 src/replication-protocol/default-conflict-handler.tsimport { deepEqual } from rxdb/plugins/utils; export const defaultConflictHandler: RxConflictHandlerany { isEqual(a, b) { // 若文档深度相等则无冲突。 // deepEqual 较耗 CPU自定义处理器可只比较 // updatedAt 或 revision 等少数属性以提升性能。 return deepEqual(a, b); }, resolve(i) { // 默认总是丢弃 fork 状态、使用 master 状态。 // 自定义处理器通常应合并 realMasterState 与 newDocumentState 的属性。 return i.realMasterState; } };要覆盖默认处理器在addCollections()创建集合时指定conflictHandler即可const myCollections await myDatabase.addCollections({ humans: { schema: mySchema, conflictHandler: myCustomConflictHandler } });关于冲突的更多背景transactions-conflicts-revisions.md 解释了 RxDB 为何不提供 ACID 事务在可随机离线的多客户端世界中事务会让整个世界停顿且无法支持 offline-first并指出每个文档带有一个类似 Lamport Clock 的 revision 字符串如1-9dcca3b8e1a写入时校验前置 revision不匹配则抛出409 CONFLICT多数情况下用incrementalModify()、incrementalPatch()、incrementalUpsert()这类增量操作即可避免本地冲突。当你希望自动合并、无需手写合并逻辑时可启用 CRDT 插件所有文档写入被表示为 JSON 格式的 CRDT 操作每次冲突时 CRDT 冲突处理器用确定性方式自动合并这些操作。CRDT 操作使用 NoSQL 更新操作符如$inc、$set底层由 mingo 库执行const myCRDTOperation { // increment the points field by 1 $inc: { points: 1 }, // set the modified field to true $set: { modified: true } };托管对比托管同步 vs 自托管ConcernInstantDBRxDBSync serviceHosted by InstantDBSelf-hosted on any stackStorage locationInstantDB cloudYour servers, your databasePricing modelPer-app hosted planCost of your own infrastructureData residencyInstantDB regionsWherever you deployOpen source serverNoYes, the protocol is open如果你想快速上线且接受托管后端InstantDB 能省去大量工作如果你的团队需要端到端掌控数据路径RxDB 允许你把同步服务器放在其他服务旁边并复用现有的认证、日志与备份设施。常见问题FAQInstantDB 可以自托管吗InstantDB 的同步服务是托管产品目前没有在自有基础设施上运行生产服务器的受支持方式。如果自托管是硬性要求RxDB 一个你已运营的后端是更接近需求的组合。RxDB 使用 Datalog 吗不使用。RxDB 使用类似 MongoDB 和 PouchDB 的 JSON Mango 语法支持 selector、排序、索引和 limit无需额外的查询语言。完整格式见 RxQuery。RxDB 如何处理乐观更新每次写入先写入本地存储并立即完成。可观察查询立即重新发出新状态UI 无需等待服务端即可更新。Sync Engine 在后台推送变更冲突经由集合的 conflict handler 处理。端到端示例见 optimistic UI。RxDB 可以自定义存储吗可以。RxDB 提供存储接口适配器包括 IndexedDB、OPFS、SQLite、内存、LocalStorage 和 Dexie。创建数据库时选择适配器其余 API 保持一致。参见 RxCollection。实时协作如何实现RxDB 通过复制事件通道从服务端流式接收变更并通过 BroadcastChannel 接收其他浏览器标签页的变更。结合 可观察查询远程变更一落地 UI 即更新。点对点场景下WebRTC 插件允许设备直接同步。架构说明见 realtime database。特性对比总表FeatureInstantDBRxDBLicenseProprietary client, hosted backendApache 2.0 coreBackendHosted Clojure sync serviceAny HTTP, GraphQL, CouchDB, Firestore, or WebRTC peerQuery languageDatalog-style triplesJSON Mango selectorsLocal layerQuery cacheFull local databaseStorage adaptersBuilt in, fixedIndexedDB, OPFS, SQLite, Memory, LocalStorage, DexieOffline writesYes, queuedYes, persisted to local storageConflict resolutionBuilt-in, limited knobsCustom handler per collection or CRDTReactivitySubscriptions on queriesRxJS observables on every queryMulti-tab syncYesYes, via BroadcastChannel or shared workerP2P syncNoYes, via WebRTC pluginSelf-hostingNot supportedStandard后续阅读如果你希望获得 InstantDB 的开发体验但要求后端可控、代码开源、底层是真正的本地数据库RxDB 值得一试。可以从 Sync Engine 文档开始了解集合如何连接到你现有的 API再阅读 reactivity 指南掌握 UI 如何保持同步。更多资源RxDB Sync EngineHTTP ReplicationCustom Conflict ResolutionCRDT SupportLocal-First FutureOptimistic UI PatternsRealtime Database赞分享数据库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点击查看免费下载相关推荐如何免费下载Steam创意工坊模组WorkshopDL完整指南如何免费下载Steam创意工坊模组WorkshopDL完整指南 还在为无法访问Steam创意工坊而烦恼吗WorkshopDL是一款功能强大的Steam创意工数据库NoSQL嵌入式数据库实时数据库抖音批量下载神器3分钟搞定1000个视频的终极指南抖音批量下载神器3分钟搞定1000个视频的终极指南 你是否曾为手动保存抖音视频而烦恼作为一名内容创作者或数据分析师面对需要下载某个博主的所有视频进行整理分数据库NoSQL嵌入式数据库实时数据库深入理解GigaChat3.5-432B-A28B的MoE机制256个专家如何协同工作深入理解GigaChat3.5 432B A28B的MoE机制256个专家如何协同工作 GigaChat3.5 432B A28B是一款采用混合专家Mixt数据库NoSQL嵌入式数据库实时数据库上一篇数据主权之战如何用AnythingLLM原生嵌入器实现100%本地向量生成下一篇Docker引擎Rootless模式深度解析以非root用户安全运行容器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表