在小程序开发中,缓存功能是提升用户体验的重要手段。但原生wx.setStorageSync API存在一个致命缺陷——存储的数据会永久保留在用户设备上,除非用户主动清除小程序数据或开发者显式调用删除方法。这种设计在实际业务场景中会引发诸多问题:
提示:微信官方文档明确说明wx.setStorageSync存储的数据没有过期机制,开发者需要自行实现时效控制
通过组合存储实现自动过期机制:
javascript复制// 存储结构示例
{
"userToken": "abcd1234", // 业务数据
"userToken_dtime": "1672531200" // 过期时间戳(Unix秒级)
}
时间精度选择:
存储键名设计:
默认时效设置:
javascript复制/**
* 设置带过期时间的缓存
* @param {String} key 存储的key值
* @param {String} value 存储的value值 (不填则默认为1)
* @param {Number} time 有效时间(单位:秒,不填则默认86400秒/24小时)
*/
function setStorageSyncSecond(key, value, time) {
value = value ? value : 1 // 默认值设置
wx.setStorageSync(key, value)
var t = time ? +time : 24 * 3600 // 默认24小时
if (t > 0) {
// 计算过期时间戳(当前时间 + 有效期)
var timestamp = Math.floor(Date.now() / 1000) + t
wx.setStorageSync(key + 'dtime', timestamp.toString())
} else {
// 永久存储则移除时间戳
wx.removeStorageSync(key + 'dtime')
}
}
javascript复制/**
* 读取带过期时间的缓存
* @param {String} key 存储的key值
* @return {*} true表示已过期/不存在,undefined表示有效
*/
function getStorageSyncTime(key) {
var deadtime = parseInt(wx.getStorageSync(key + 'dtime'))
if (deadtime) {
var current = Math.floor(Date.now() / 1000)
if (deadtime < current) {
// 自动清理过期数据
wx.removeStorageSync(key)
wx.removeStorageSync(key + 'dtime')
return true
}
} else {
// 无时间戳记录视为过期
return true
}
}
javascript复制// 登录成功后存储token(有效期7天)
setStorageSyncSecond('authToken', res.token, 7 * 24 * 3600)
// 检查token是否有效
function checkAuth() {
if (getStorageSyncTime('authToken') === true) {
// token过期或不存在
navigateToLogin()
} else {
// token有效
return wx.getStorageSync('authToken')
}
}
javascript复制// 获取活动配置(缓存2小时)
function getActivityConfig() {
if (getStorageSyncTime('activityConfig') !== true) {
return wx.getStorageSync('activityConfig')
}
// 从服务器获取最新配置
api.getActivityConfig().then(res => {
setStorageSyncSecond('activityConfig', res.data, 7200)
return res.data
})
}
定期清理策略:
javascript复制// 应用启动时清理所有过期缓存
function clearExpiredStorages() {
const keys = wx.getStorageInfoSync().keys
keys.forEach(key => {
if (key.endsWith('dtime')) {
const mainKey = key.replace('_dtime', '')
getStorageSyncTime(mainKey) // 触发自动清理
}
})
}
容量监控:
javascript复制// 检查存储使用情况
const { currentSize, limitSize } = wx.getStorageInfoSync()
if (currentSize > limitSize * 0.7) {
// 触发主动清理
}
存储失败处理:
javascript复制try {
wx.setStorageSync(key, value)
} catch (e) {
console.error('存储失败:', e)
// 降级方案:尝试移除旧数据后重试
}
数据类型转换:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 客户端时效控制 | 减少网络请求,响应快 | 时间依赖客户端时钟 |
| 服务端校验 | 可靠性高 | 每次请求需要网络验证 |
| 策略 | 适用场景 | 实现复杂度 |
|---|---|---|
| 时效缓存 | 临时数据、配置信息 | 中等 |
| LRU缓存 | 高频访问数据 | 较高 |
| 永久缓存 | 用户偏好设置 | 低 |
时间戳异常问题:
键名冲突问题:
iOS/Android差异:
在实际项目中使用这套方案时,我建议将缓存操作封装成独立模块,并添加完整的日志记录。这样当出现异常时,可以通过日志快速定位是存储失败、提前过期还是其他问题。同时要注意测试不同设备上的兼容性表现,特别是低端安卓设备上的性能表现。