
小程序里做数据缓存,常见坑是存了 token 却读不到、退出登录后旧数据仍在、列表缓存后再不更新。根源是把本地存储当黑盒,没分清同步与异步的边界,也没为小程序数据缓存设计过期与清理机制。本文讲清取舍场景,并给出可直接复用的封装。
一、同步与异步存储的取舍
小程序存储把数据写到设备沙箱,卸载即清除,按 key-value 保存,单个 key 建议不超过 1MB,总量上限 10MB。
1. 什么时候必须用异步
异步 API 不阻塞线程,适合读写大对象或批量写多个 key。同步写 1MB 会卡住渲染主线程,在 onLoad 里连写多条缓存时首屏容易白屏。
// 异步写入:不阻塞渲染
wx.setStorage({ key: 'token', data: token, success: () => console.log('ok') })
2. 什么时候用同步更省事
同步 API 适合读小字段就立即决策的场景,比如启动时读 token 决定是否跳登录页。同步读超大 value 会抛异常,包一层 try-catch 更稳。
二、给缓存加上过期时间
原生 API 只管存取,不提供过期机制。不自己加时间戳,缓存会长期留在设备上。
1. 存储结构与写入封装
用带前缀的 key 区分业务缓存,value 存成 {v, exp} 结构:v 是真实数据,exp 是到期时间戳,0 表示永不过期。
// 写入时附加到期时间戳
const PREFIX = 'cache:'
function setCache(key, value, ttl) { // ttl 单位秒
const payload = { v: value, exp: ttl ? Date.now() + ttl * 1000 : 0 }
wx.setStorageSync(PREFIX + key, payload)
}
2. 读取校验与惰性删除
读取时先解出 exp,已过期就顺手删除并返回 null,让调用方回源请求。惰性删除不用定时器,成本最低。
function getCache(key) {
const raw = wx.getStorageSync(PREFIX + key)
if (!raw) return null
if (raw.exp && raw.exp < Date.now()) { // 已过期
wx.removeStorageSync(PREFIX + key)
return null
}
return raw.v
}
三、容量限制与清理策略
缓存写多了会顶到 10MB 上限,届时 setStorage 直接失败,不如主动治理。
1. 单个 key 与总容量上限
列表类数据最易超标,把 500 条商品 JSON 塞进一个 key 就可能超过 1MB。这类数据只缓存必要字段,或分页拆成多个 key。
2. 缓存过期清理与长期驻留治理
除惰性删除,可在 App.onLaunch 里做一次全量扫描,复用上面的读取逻辑批量清理,避免冷启动后容量被历史数据占满。
// 遍历所有业务 key,复用 getCache 的惰性删除
function cleanExpired() {
wx.getStorageInfoSync().keys
.filter(k => k.startsWith(PREFIX))
.forEach(k => getCache(k.slice(PREFIX.length)))
}
容量紧张时还可记录 lastUsed 时间戳,按最久未使用优先淘汰,即 LRU 思路。中小项目用「过期时间 + 启动清理」已够用。
关键配置提示
- 单个 key 不超过 1MB,总量 10MB;列表数据只存必要字段或分页拆 key。
- 同步 API 只读小字段做渲染前决策,大对象与批量写走异步。
- 业务缓存加统一前缀,配合 {v, exp} 与启动清理,避免脏数据长期驻留。

快来评论,快来抢沙发吧~