news 2026/9/19 19:27:04

leetcode-patterns 实时同步原理:防抖上传与 Realtime 合并,杜绝多设备数据冲突

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
leetcode-patterns 实时同步原理:防抖上传与 Realtime 合并,杜绝多设备数据冲突

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 秒定时器
  2. 定时器到期前又来一次操作?清掉旧定时器,重新计时
  3. 直到你停手 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)。

逐字段比对:无变化就不落盘

completedstarrednotessolved_datesreminders五个字段逐一与本地状态比对(setsEqual / recordsEqual),只有真正有差异才写 localStorage,并递增syncVersion通知表格组件重读本地数据、刷新界面。这避免了无意义的状态抖动和界面闪烁。

完整的多设备同步时序

  1. 打开网站 / 登录downloadAndMerge()拉取远端快照,远端是"真相之源"直接覆盖本地;若远端还没有数据,则把本地先推上去(src/lib/sync.ts#L36-L57)
  2. 本机操作→ 写 localStorage → 防抖计时 1 秒
  3. 停止操作upsert到云端,记录lastUploadAt
  4. Realtime 广播→ 其他设备收到 → 5 秒窗口判断 → 逐字段合并 → 界面刷新
  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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 19:21:45

Java与PHP源码审计双线实战:从应急响应到漏洞溯源

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 19:18:42

机器学习大作业全流程指南:数据预处理、模型选择与评估调参

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华