本地缓存是副本,数据库为唯一数据源;读取时先本地再校验,写入时先落库后清缓存,多端靠version+storage事件协同,容错需时间戳、乐观锁与静默同步。

持久化存储与后端接口同步,核心在于明确“谁主谁从”和“何时更新”。本地缓存是副本,数据库才是唯一数据源;同步不是自动发生的,必须由业务逻辑主动控制读写时机和顺序,否则极易出现旧数据覆盖新状态、多端显示不一致等问题。
读取时:先本地、再校验、必要时回源
用户打开页面时,优先从 localStorage 或 sessionStorage 读取缓存数据,快速渲染界面。但不能直接信任它——尤其当数据可能被其他设备或标签页修改过时。
- 对关键业务数据(如用户信息、订单状态),在读取本地缓存后,发起轻量级接口请求(例如带版本号或时间戳的 GET /user?_t=1742988360)校验是否过期
- 若响应返回“未变更”,继续使用本地数据;若返回新数据,则更新本地缓存并刷新视图
- 可结合 ETag 或 Last-Modified 做条件请求,减少无效传输
写入时:先落库、再清缓存(推荐)或双写(慎用)
用户提交表单、修改设置、删除记录等操作,必须以数据库写入成功为前提,再处理本地缓存。
- 删除缓存策略(更安全):更新数据库成功后,调用 localStorage.removeItem('user_profile') 或 sessionStorage.clear()。下次读取会自然触发回源拉取最新数据
- 双写策略(需兜底):数据库更新成功后,立即写入新值到 localStorage.setItem('user_profile', JSON.stringify(data))。但必须加 try-catch,失败时记录日志并触发后续补偿任务
- 避免“先删缓存、再改库”——万一改库失败,缓存空缺期间所有请求都会打到数据库,还可能误读旧快照
多端/多标签页场景:靠事件监听 + 版本标识协同
单一浏览器标签页内可控,但用户可能同时在手机 App、微信小程序、另一个 Chrome 标签页操作同一账号。这时仅靠 localStorage 监听 storage 事件不够。
- 在 localStorage 中额外存一个 version 字段(如 timestamp 或 UUID),每次写入数据库后更新该版本
- 各端监听 storage 事件,发现 version 变化,就主动触发一次全量或增量同步(例如 GET /sync?since=1742988350)
- 微信小程序用 wx.onAppShow + wx.getStorageSync 配合后端心跳接口判断登录态是否失效
- Jotai 的 atomWithStorage 已内置 storage 事件监听,但仅限同源标签页,跨端仍需服务端协调
容错与兜底:网络异常、写入失败、版本冲突都要有应对
真实环境里,网络抖动、IndexedDB 写满、用户手动清缓存都可能发生,不能假设一切顺利。
- 所有写操作完成后,本地缓存应附带写入时间(write_ts)和来源标记(source: 'backend'),便于排查脏数据
- 前端启动时检查缓存有效期(比如超过 10 分钟未更新),自动触发一次静默同步
- 对高冲突风险操作(如多人协作文档),引入乐观锁:请求头带 if-match: ETag,后端比对失败则返回 412,前端提示“内容已被他人修改”,引导用户刷新或合并
- 定期运行清理脚本:localStorage 中过期 key(如带 expireAt 字段)自动移除,避免缓存膨胀








