高可用Web应用需从数据分层、冲突策略、同步时机和降级机制四方面系统设计:分层存储按生命周期选介质;离线写入用带状态追踪的IndexedDB队列;冲突按业务语义分级解决;降级机制保障用户感知与可观测性。

要构建高可用 Web 应用,客户端存储与离线同步不能只靠 localStorage 加个轮询,得从数据分层、冲突策略、同步时机和降级机制四方面系统设计。
分层存储:按生命周期和用途选介质
不同数据对持久性、容量、访问速度要求不同,混用会出问题:
-
瞬态状态(如表单草稿、UI 展开收起)→ 用
sessionStorage或内存对象,关闭即丢,不参与同步 -
用户关键数据(如待提交订单、收藏项)→ 存
IndexedDB,支持事务、索引、大容量;避免直接塞进 localStorage(5MB 限制 + 同步阻塞) -
只读缓存(如字典、配置、静态资源元信息)→ 用
Cache API配合 Service Worker,支持版本化与精准失效 -
加密敏感字段(如 token 片段、本地偏好密钥)→ 不直接存明文,用
SubtleCrypto在 IndexedDB 中加密后落盘
离线写入与同步调度:带状态追踪的可靠队列
用户离线时所有变更必须可追溯、可重放、不丢失:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 每条本地操作生成唯一
opId,记录timestamp、entityType、action(create/update/delete)、payload和serverVersion(用于乐观并发控制) - 同步队列存在 IndexedDB 中,带
status: pending | syncing | synced | failed字段;失败任务保留并指数退避重试(如 1s → 3s → 9s) - 同步触发时机不止是“联网后”:页面可见时、后台 tab 切回前台时、定时检查(如每 5 分钟)都应触发一次轻量探测
- 避免全量同步:用时间戳或序列号增量拉取服务端变更(
since=1728432000),再合并本地未同步操作
冲突解决:按业务语义做策略,不依赖时间戳硬覆盖
两个用户同时改同一字段,自动合并不是万能解:
- 对 非结构化内容(如富文本编辑)→ 用 OT(Operational Transformation)或 CRDT 库(如
yjs)实现协同一致性 - 对 数值型字段(如库存、计数器)→ 用服务端原子操作(
incr/decr)+ 客户端预估值,同步后校准 - 对 强互斥操作(如订单支付、座位锁定)→ 客户端先申请锁(
POST /lock?resource=seat-12A),失败则立即提示,不写本地 - 所有冲突需记录日志(含本地/服务端版本、操作人、时间),供前端展示差异并引导人工选择
降级与可观测:让用户感知“正在努力”,而非卡死或静默失败
高可用不只是技术指标,更是用户可感知的韧性:
- 网络恢复后自动同步,但同步中禁用重复提交按钮,并显示「正在同步您的修改…」,失败时明确提示「已保存至本地,稍后重试」
- 在 DevTools 控制台或专用调试面板暴露同步队列长度、最近错误、离线时长等指标,方便 QA 和一线支持快速定位
- 对长期离线(如 >24 小时)场景,主动提醒用户检查网络,并提供「导出本地数据」按钮(JSON 格式),避免数据孤岛
- Service Worker 捕获 fetch 失败时,优先返回 Cache API 缓存的旧数据(stale-while-revalidate),再后台刷新,保证界面始终可交互

















