Files
past-go/weapp/utils/data-cache.js
T
2026-10-26 17:32:47 +08:00

89 lines
4.2 KiB
JavaScript

// 仅保存本次进程内的数据,不写入手机本地存储。
const TTL = 45000;
const policies = {
coupleInfo: 300000, getBgConfig: 300000,
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;
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 = {}; epoch++; }
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(groups.timeline.concat(groups.diary, groups.checkin));
}
module.exports = { read, invalidate, mutation, clear, signature, policies, TTL };