leetcode-patterns 实时同步原理:防抖上传与 Realtime 合并,杜绝多设备数据冲突
【免费下载链接】leetcode-patternsA pattern-based approach to learn technical interview questions项目地址: https://gitcode.com/gh_mirrors/le/leetcode-patterns
leetcode-patterns 是一个基于模式分类的 LeetCode 面经刷题工具。这篇文章拆解它的实时同步机制:如何靠「防抖上传 + Realtime 合并」,让你在不同设备上的完成状态、笔记和复习提醒保持一致,彻底杜绝多设备数据冲突。
多设备刷题为什么需要同步机制?
想象一下真实场景:
- 🚇 地铁上用手机勾掉 3 道题,回家后打开电脑,进度却还没跟上
- 💻 笔记本上刚写的解题笔记,手机端看不到
- ⚠️ 如果每次点击都立刻写回服务端,高频操作会互相覆盖,产生"数据冲突"
leetcode-patterns 的进度数据(已完成题目、星标、笔记、解题日期、复习提醒)就存在每个用户的 user_progress 快照里。它不追求"每次操作都同步",而是用三层机制协作,做到既流畅又一致。
同步全景:本地优先 + 防抖上传 + Realtime 合并
| 层级 | 职责 | 源码位置 |
|---|---|---|
| ① 本地优先 | 每次操作先写浏览器 localStorage,操作永远零延迟 | src/lib/storage.ts |
| ② 防抖上传 | 1 秒内的多次操作合并成一次上传 | src/lib/sync.ts |
| ③ Realtime 合并 | 服务端把变更实时推送给其他设备,本地比对后合并 | src/lib/sync.ts |
防抖上传:1 秒缓冲期,合并高频写入
每次你勾选"已完成"、加星标或保存笔记,组件都会调用syncNow()→scheduleUpload(userId),例如 QuestionsTable.tsx 中的 toggleCompleted。
scheduleUpload的实现非常克制:
- 收到请求后启动一个1 秒定时器
- 定时器到期前又来一次操作?清掉旧定时器,重新计时
- 直到你停手 1 秒,才真正执行一次
upsert写入 user_progress 表
也就是说,连续刷 20 题只需 1 次网络请求,且写入按onConflict: user_id保证每个用户只有一行记录,天然避免覆盖竞争。
离场兜底:关页面前立即冲刷待发数据
如果 1 秒内你就关闭了页面,数据会丢吗?不会。AuthProvider 注册了两个钩子:
beforeunload:页面即将关闭visibilitychange:页面切到后台(比如切 App、锁屏)
两者都会触发 flushPendingUpload(),把待发上传立即冲刷出去,保证"刷新即最新"。
Realtime 合并:其他设备的改动秒级到达
登录后,客户端通过 Supabase Realtime 订阅user_progress表,并且只监听属于自己user_id的 UPDATE 事件(见 AuthContext.tsx 的频道订阅)。收到推送后交给mergeFromRealtimePayload()本地合并,不发起任何额外请求。
5 秒自过滤窗口:避免"自己回显自己"
上传成功后,服务端会把这次 UPDATE 广播给该用户的所有在线设备——包括刚上传的这台。如果直接合并,就等于用"旧状态"覆盖自己。
mergeFromRealtimePayload用一个lastUploadAt时间戳解决:事件到达时若距本机上次上传不足 5 秒,判定为自己的回显,直接跳过(src/lib/sync.ts#L94-L96)。
逐字段比对:无变化就不落盘
对completed、starred、notes、solved_dates、reminders五个字段逐一与本地状态比对(setsEqual / recordsEqual),只有真正有差异才写 localStorage,并递增syncVersion通知表格组件重读本地数据、刷新界面。这避免了无意义的状态抖动和界面闪烁。
完整的多设备同步时序
- 打开网站 / 登录→
downloadAndMerge()拉取远端快照,远端是"真相之源"直接覆盖本地;若远端还没有数据,则把本地先推上去(src/lib/sync.ts#L36-L57) - 本机操作→ 写 localStorage → 防抖计时 1 秒
- 停止操作→
upsert到云端,记录lastUploadAt - Realtime 广播→ 其他设备收到 → 5 秒窗口判断 → 逐字段合并 → 界面刷新
- 关页 / 切后台→
flushPendingUpload()冲刷最后写入
整个过程无需用户手动"保存"或"刷新",进度在多设备间自动对齐。核心逻辑还有完整的单元测试覆盖,见 src/lib/sync.test.ts。
关键源码速查
- 防抖上传与冲刷:src/lib/sync.ts
- Realtime 载荷合并:src/lib/sync.ts
- Realtime 频道订阅与会话同步:src/components/layout/AuthContext.tsx
- 各操作触发上传的组件:src/components/questions/QuestionsTable.tsx
一句话总结
💡 leetcode-patterns 的实时同步本质是三件套:本地优先保证流畅、防抖上传合并高频写、Realtime 推送 + 5 秒自过滤 + 逐字段比对保证合并正确。三层各司其职,让"多设备刷题"这件事零感知、零冲突。
【免费下载链接】leetcode-patternsA pattern-based approach to learn technical interview questions项目地址: https://gitcode.com/gh_mirrors/le/leetcode-patterns
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考