// 仅保存本次进程内的数据,不写入手机本地存储。 const TTL = 300000; const policies = { coupleInfo: TTL, getBgConfig: TTL, myInfo: TTL, storageInfo: TTL, announcement: TTL, checkAuth: 30000, unbindStatus: 30000, timelineList: TTL, timelineDetail: TTL, albumList: TTL, photos: TTL, diaryList: TTL, diaryDetail: TTL, diaryCommentList: TTL, songsList: TTL, checkinList: TTL, checkinStats: TTL, checkinDetail: TTL, smokingInfo: TTL, petInfo: TTL, petAchievements: TTL, activityLogList: TTL }; const groups = { couple: ['coupleInfo'], timeline: ['timelineList', 'timelineDetail'], album: ['albumList', 'photos'], diary: ['diaryList', 'diaryDetail', 'diaryCommentList'], songs: ['songsList'], checkin: ['checkinList', 'checkinStats', 'checkinDetail'], pet: ['petInfo', 'petAchievements'], background: ['getBgConfig'] }; let entries = new Map(); let versions = {}; let scope = ''; let epoch = 0; let remoteRevision; function currentScope() { const next = String(wx.getStorageSync('userId') || '') + ':' + String(wx.getStorageSync('coupleId') || ''); if (next !== scope) { scope = next; clear(); } return scope; } function clear() { entries.clear(); versions = {}; remoteRevision = undefined; epoch++; } function applyRemoteRevision(revision) { currentScope(); if (!revision) return false; if (remoteRevision === undefined) { remoteRevision = revision; return false; } if (remoteRevision === revision) return false; clear(); remoteRevision = revision; return true; } function signature(actions) { currentScope(); return epoch + ':' + actions.map(action => action + ':' + (versions[action] || 0)).join('|'); } function invalidate(actions) { currentScope(); actions.forEach(action => { versions[action] = (versions[action] || 0) + 1; }); entries.forEach((entry, key) => { if (actions.indexOf(entry.action) >= 0) entries.delete(key); }); } function stable(value) { if (Array.isArray(value)) return value.map(stable); if (value && typeof value === 'object') { const out = {}; Object.keys(value).sort().forEach(key => { if (value[key] !== undefined && value[key] !== null) out[key] = stable(value[key]); }); return out; } return value; } function copy(value) { return value == null ? value : JSON.parse(JSON.stringify(value)); } async function read(action, data, fetch) { currentScope(); if (!policies[action]) return fetch(); const key = action + ':' + JSON.stringify(stable(data || {})); let entry = entries.get(key); if (entry && entry.pending) return entry.pending.then(copy); if (entry && Date.now() - entry.time < policies[action]) return copy(entry.value); entry = { action }; // 不缓存失败;失效或身份切换后,旧请求不能写回缓存。 entries.set(key, entry); entry.pending = Promise.resolve().then(fetch).then(value => { if (entries.get(key) === entry) { entry.value = copy(value); entry.time = Date.now(); entry.pending = null; // 限制详情/分页缓存数量,避免长时间浏览占用过多内存。 if (entries.size > 150) entries.delete(entries.keys().next().value); } return value; }, error => { if (entries.get(key) === entry) entries.delete(key); throw error; }); return entry.pending.then(copy); } function mutation(action, result) { if (result && (result.error || result.success === false)) return; if (/^(logout|respondInvitation|acceptShareInvite|unbindRequest|unbindRespond|unbindCancel)$/.test(action)) { clear(); return; } let group; if (/^(updateProfile|updatePartnerProfile|updateCoupleInfo|updateLocation|updateIpLocation|uploadAvatar|uploadPartnerAvatar)$/.test(action)) group = 'couple'; else if (/^timeline(Add|Update|Delete)$/.test(action)) group = 'timeline'; else if (/^(album(Add|Update|Delete)|photo(Add|Update|Delete|Upload))$/.test(action)) group = 'album'; else if (/^diary(Add|Update|Delete|CommentAdd|CommentDelete)$/.test(action)) group = 'diary'; else if (/^songs(Add|Update|Delete)$/.test(action)) group = 'songs'; else if (action === "smokingAction") { invalidate(["smokingInfo"]); group = "checkin"; } else if (/^checkin(Add|Do|Delete)$/.test(action)) { invalidate(groups.pet); group = 'checkin'; } else if (/^pet(Adopt|DailyAction|Rename)$/.test(action)) group = 'pet'; else if (/^(setBgImage|deleteBgImage)$/.test(action)) group = 'background'; if (group) invalidate(groups[group].concat(['activityLogList'])); if (group === 'couple') invalidate(['myInfo','checkAuth']); if (action === 'smokingCardVisible') invalidate(['checkAuth','myInfo']); if (/^(upload|photoUpload|uploadAvatar|uploadPartnerAvatar|setBgImage|deleteBgImage|setAlbumCover|photoDelete|albumDelete|accountDelete)$/.test(action) || (action === 'storageOrderStatus' && result && result.status === 'paid')) invalidate(['storageInfo']); // 展示作者资料的列表也需要更新头像/昵称。 if (group === 'couple') invalidate(groups.timeline.concat(groups.diary, groups.checkin)); } module.exports = { read, invalidate, mutation, clear, signature, policies, TTL, applyRemoteRevision };