ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 ShareDB 构建实时排行榜:Leaderboard 示例应用全解析

用 ShareDB 构建实时排行榜:Leaderboard 示例应用全解析 后端数据库【免费下载链接】sharedbRealtime database backend based on Operational Transformation (OT)项目地址https://gitcode.com/gh_mirrors/sh/sharedb点击查看免费下载导读Leaderboard排行榜是 ShareDB 仓库内置的 React 示例应用演示如何基于 Operational TransformationOT构建一个多用户实时协作的计分板任何人选中一位科学家并点击加分会所有打开页面的浏览器都会实时同步看到分数变化与排名重排。本文以 examples/leaderboard/README.md 为骨架结合该示例的完整源码讲解它的服务端架构、WebSocket 桥接、实时查询、OT 操作提交与 React 渲染管线并说明如何把它从内存数据库切换到 Mongo 实现数据持久化。读完本文你将掌握 ShareDB 从启动后端 → 播种数据 → 客户端订阅 → 提交操作 → 界面实时刷新的完整链路。一、示例定位从 React Leaderboard 到 ShareDB 的移植Leaderboard 是经典的 Meteor 演示应用percolatestudio 出品的 React Leaderboard在 ShareDB 上的移植版本目标是在一个极简的应用里完整展现 ShareDB 的核心能力多人实时协作分数变更即时广播给所有已连接客户端查询结果实时更新按分数倒序的排名列表会随任何一次操作自动重排OT 冲突处理多个用户同时对同一文档提交操作时由 ShareDB 的 OT 机制保证最终一致无需手动加锁。示例的默认配置是数据不持久化它使用sharedb-mingo-memory内存数据库服务重启后排行榜数据即丢失README 明确说明 data is not persisted。若需持久化官方给出的方案是启动一个 MongoDB 服务并在初始化 ShareDB 时改用sharedb-mongo数据库适配器详见本文第五节。二、快速上手安装、构建与运行整个示例是独立的 npm 工程其依赖清单位于 examples/leaderboard/package.json运行前请先进入该目录README 特别强调必须在examples/leaderboard目录内执行以保证使用的是该目录下的package.json。1. 安装依赖npm install核心依赖一览来自package.json依赖作用sharedb^3.3.0ShareDB 核心库服务端Backend与客户端Connection均由它提供sharedb-mingo-memory^2.1.2内存数据库适配器本示例默认的数据存储层teamwork/websocket-json-stream^2.0.0把 WebSocket 包装成 ShareDB 所需的 JSON 流ws^8.12.1Node.js 原生 WebSocket 服务端实现reconnecting-websocket^4.4.0浏览器端支持自动重连的 WebSocket 客户端express^4.18.2静态文件服务与 HTTP 服务器react/react-dom^18.2.0前端 UI 框架browserifybabelifybabel/preset-react将 JSX 源码打包为浏览器可执行的 bundle2. 构建前端 bundle 并启动服务npm run build npm startnpm run build执行 package.json 中定义的脚本browserify -t [ babelify --presets [ babel/react ] ] client/index.jsx -o static/dist/bundle.js把client/目录下的 JSX 组件编译打包到static/dist/bundle.jsnpm start执行node server/index.js启动后端服务。3. 打开浏览器访问默认监听8080 端口直接访问http://localhost:8080页面会展示一份按分数倒序排列的科学家排行榜。要体验实时性请务必打开两个或更多浏览器窗口在一个窗口选中某人加 5 分另一个窗口会看到分数与排名即时变化——这正是 README 给出的测试建议。三、服务端实现内存数据库 WebSocket 桥接 初始数据播种服务端入口是 examples/leaderboard/server/index.js仅约 40 行代码却完整覆盖了 ShareDB 服务的三个关键环节。3.1 初始化 ShareDB 与内存数据库var share new ShareDB({db: new ShareDBMingoMemory()});ShareDBMingoMemory是 ShareDB 官方提供的内存数据库适配器实现了 ShareDB 的数据库接口commit、getSnapshot、query等。把它传入ShareDB构造函数即得到可以直接listen的 ShareDB 后端实例。由于它是纯内存实现进程退出即数据清零这也是数据不持久化的直接原因。3.2 用 WebSocket 桥接 ShareDBvar app express(); app.use(express.static(static)); var server http.createServer(app); var wss new WebSocket.Server({server: server}); server.listen(8080); wss.on(connection, function(ws) { var stream new WebSocketJSONStream(ws); share.listen(stream); });这里的关键是把 WebSocket 连接包装成 ShareDB 认识的流对象teamwork/websocket-json-stream负责把ws的双向消息转换成 JSON 流share.listen(stream)则让每个 WebSocket 连接直接挂接进 ShareDB 的消息处理管线。express.static(static)同时把前端页面含构建产物static/dist/bundle.js作为静态资源对外提供因此单一端口 8080 同时承担了页面托管与实时数据通道。3.3 首次启动时播种排行榜数据var connection share.connect(); connection.createFetchQuery(players, {}, {}, function(err, results) { if (err) throw err; if (results.length 0) { var names [Ada Lovelace, Grace Hopper, Marie Curie, Carl Friedrich Gauss, Nikola Tesla, Claude Shannon]; names.forEach(function(name, index) { var doc connection.get(players, index); var data {name: name, score: Math.floor(Math.random() * 10) * 5}; doc.create(data); }); } });值得注意的细节share.connect()创建的连接与客户端连接走的是同一套 ShareDB 协议服务端可以用它作为程序化客户端来准备初始数据createFetchQuery(players, {}, {}, ...)查询players集合的全部文档仅在结果为空时才执行播种保证多次重启后不会重复插入每个文档的结构是{name: 姓名, score: 随机分数}其中score为0~45之间以 5 为步长的随机数为排行榜的初始排序提供多样性文档 ID 是字符串形式的索引0、1…客户端后续通过connection.get(players, id)精确获取同一文档。四、客户端实现重连连接、实时查询与 OT 操作4.1 单例 WebSocket 连接sharedb.Connectionexamples/leaderboard/client/connection.js 建立了一个进程内共享的 ShareDB 连接单例var socket new ReconnectingWebSocket(ws:// window.location.host, [], { maxEnqueuedMessages: 0 }); var connection new sharedb.Connection(socket); module.exports connection;使用reconnecting-websocket提供断线自动重连能力maxEnqueuedMessages: 0是刻意为之ShareDB 自己会处理丢消息与重连后的状态同步若同时在 WebSocket 层缓冲消息会带来语义不明的行为源码注释原话ShareDB handles dropped messages, and buffering them while the socket is closed has undefined behaviornew sharedb.Connection(socket)构造的是 ShareDB 的客户端连接对象后续的查询、文档订阅、操作提交都经由它完成。4.2 实时查询createSubscribeQuery 驱动榜单排序榜单组件 examples/leaderboard/client/Leaderboard.jsx 在componentDidMount中发起带排序的订阅查询var query connection.createSubscribeQuery(players, {$sort: {score: -1}}); query.on(ready, update); query.on(changed, update); function update() { comp.setState({players: query.results}); }{$sort: {score: -1}}请求服务端按score降序返回这就是排行榜排名的数据来源createSubscribeQuery与一次性createFetchQuery的区别在于它会在服务端持续追踪匹配该查询的文档任一文档变更如分数增加都可能使results变化并触发changed事件组件监听ready首次加载完成与changed结果变化两个事件统一通过setState({players: query.results})驱动 React 重渲染componentWillUnmount中调用query.destroy()释放订阅避免组件卸载后残留服务端订阅。4.3 提交 OT 操作给分数加 5加分的核心逻辑同样在 Leaderboard.jsxhandleAddPoints() { var op [{p: [score], na: 5}]; connection.get(players, this.state.selectedPlayerId).submitOp(op, function(err) { if (err) { console.error(err); return; } }); }这段代码是理解 ShareDB 数据模型的关键connection.get(players, id)取得目标文档的客户端引用再调用submitOp提交一条 json0 操作操作[{p: [score], na: 5}]是 json0 操作类型的数字加na numeric addp指定路径为score字段na: 5表示对该字段的值增加 5操作提交后由服务端校验、落库并广播给所有订阅了该文档/查询的其他客户端各端通过 OT 变换保证并发操作下的数据一致性加分按钮只对当前选中的玩家生效selectedPlayerIdPlayerSelector组件在未选中任何人时只显示提示文字 Click a player to select。4.4 单文档订阅与局部刷新Player 组件examples/leaderboard/client/Player.jsx 演示了单个文档粒度的实时订阅componentDidMount() { var doc comp.props.doc; doc.subscribe(); doc.on(load, update); doc.on(op, update); function update() { // comp.props.doc.data is now updated. re-render component. comp.forceUpdate(); } } componentWillUnmount() { this.doc.unsubscribe(); }doc.subscribe()让客户端持续接收该文档的操作流doc.on(op)在每次远端操作被本地应用后触发渲染时直接读取this.props.doc.data.name/this.props.doc.data.score——data始终是应用了所有已到达操作的文档快照所以forceUpdate()即可呈现最新状态componentWillUnmount中unsubscribe()与组件生命周期成对出现避免泄漏订阅组件通过点击事件onPlayerSelected(doc.id)把选中状态上抛给Leaderboard实现点谁给谁加分的交互。其余展示组件Body.jsx、PlayerList.jsx、PlayerSelector.jsx只负责纯展示与事件回调不直接与 ShareDB 交互页面入口 client/index.jsx 使用 React 18 的createRoot挂载应用。五、数据持久化从内存数据库切换到 MongoREADME 明确指出默认情况下数据不会持久化要让数据在重启后保留需要运行一个 Mongo 服务器并改用sharedb-mongo适配器初始化 ShareDB。官方推荐的改造方式只需替换 server/index.js 中的数据库初始化一行// 改造前内存数据库 var ShareDBMingoMemory require(sharedb-mingo-memory); var share new ShareDB({db: new ShareDBMingoMemory()}); // 改造后MongoDB 持久化需 npm install sharedb-mongo var ShareDBMongo require(sharedb-mongo); var share new ShareDB({db: new ShareDBMongo(mongodb://localhost:27017/leaderboard)});改造要点本地需先启动 MongoDB 服务连接串含数据库名按实际环境调整依赖上新增sharedb-mongo移除或保留sharedb-mingo-memory均可其余代码WebSocket 桥接、初始播种逻辑、客户端完全无需改动因为 ShareDB 通过统一的数据库接口抽象屏蔽了底层差异——这正是适配器设计带来的收益注意示例中的播种逻辑基于players集合查询结果为空判断切到 Mongo 后首次启动仍会自动写入六个科学家的初始数据之后便从 Mongo 读取。ShareDB 数据库适配器的接口定义可参考 lib/db/index.js 与官方数据库实现如sharedb-mongo、sharedb-mingo-memory的对应关系想了解内存适配器行为的读者也可以对照 lib/db/memory.js 阅读。六、整体流程回顾与实验建议把前面各节串起来Leaderboard 的实时链路如下服务端server/index.js启动 ShareDB内存库监听 8080首次启动播种 6 名科学家的随机分数浏览器加载页面connection.js建立带自动重连的 WebSocket 连接Leaderboard.jsx发出createSubscribeQuery(players, {$sort: {score: -1}})每个Player组件对其文档执行subscribe()ready/changed/op事件把最新分数与排名同步到 React 状态用户点击Add 5 pointssubmitOp([{p:[score], na: 5}])经 WebSocket 提交到服务端OT 引擎变换、落库或落内存后广播所有在线窗口的查询结果集与文档快照同步更新排行榜即时重排。推荐实验步骤README 的建议打开两个浏览器窗口访问http://localhost:8080在窗口 A 中选中一位科学家点击加分观察窗口 B 中该玩家的分数与排名无需刷新即同步变化在两个窗口快速交替加分观察并发操作下榜单最终仍保持一致OT 生效重启npm start后刷新页面确认默认内存库下数据已重置——再按第五节改造接入 Mongo 后重启数据得以保留。七、局限与延伸数据不持久化是默认行为而非缺陷内存库让示例零依赖即可运行适合快速体验实时链路生产场景应接入 Mongo或实现 lib/db/index.js 规定的数据库接口的其他存储示例刻意简化了错误处理如handleAddPoints仅console.error、认证鉴权与横向扩展这些属于接入真实业务时需要补充的工程能力想深入 ShareDB 协议与 OT 细节可继续阅读仓库的 docs/getting-started.md、docs/api/index.md 与 lib/ot.js仓库中 examples/counter、examples/rich-text 等示例覆盖了不同操作类型与使用场景可与本示例对照学习。赞分享后端数据库【免费下载链接】sharedbRealtime database backend based on Operational Transformation (OT)项目地址https://gitcode.com/gh_mirrors/sh/sharedb点击查看免费下载相关推荐ShareDB实战指南如何快速构建多人协作的实时排行榜系统ShareDB实战指南如何快速构建多人协作的实时排行榜系统 想要构建一个支持多人实时协作的Web应用ShareDB正是你需要的 实时数据库后端 解决方案基后端数据库三步配置免费 arXiv 论文个性化订阅让 Zotero-arXiv-Daily 按你的 Zotero 图书馆选文三步配置免费 arXiv 论文个性化订阅让 Zotero arXiv Daily 按你的 Zotero 图书馆选文 每天打开 arXiv新论文列表一眼望不到人工智能AI 应用RAG科研DiceDB Q.WATCH 命令全解析用 DSQL 查询订阅构建实时排行榜DiceDB Q.WATCH 命令全解析用 DSQL 查询订阅构建实时排行榜 导读 Q.WATCH 是 DiceDB 提供的一项查询订阅query subs数据库缓存后端上一篇iOS激活锁绕过终极指南3步使用Applera1n免费解锁iPhone下一篇BlueArchive-Cursors为你的Windows桌面注入二次元灵魂创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表