perf: Sliding-window Cache — Hintergrund-Prefetch bei Cache-Randnähe

Wenn die aktuelle Ansicht weniger als 4 Wochen vom Cache-Rand entfernt
ist, werden im Hintergrund 8 weitere Wochen in diese Richtung geladen
und in den Cache gemergt. Der Cache wächst damit automatisch mit der
Navigation mit — kein sichtbarer Ladevorgang auch bei langen Sprüngen.
This commit is contained in:
Scarriffle
2026-04-07 22:09:11 +02:00
parent faada7359e
commit d8ec22d573

View File

@@ -73,12 +73,54 @@ export async function initCalendar() {
}
// ── Event cache ───────────────────────────────────────────
const eventCache = { start: null, end: null, events: [] };
const CACHE_BUF = 56 * 86400000; // initial ±8 weeks
const PREFETCH_EXT = 56 * 86400000; // extend by 8 weeks when triggered
const PREFETCH_EDGE = 28 * 86400000; // trigger when within 4 weeks of cache edge
const eventCache = {
start: null, end: null, events: [],
_fwdPending: false, _bwdPending: false,
};
function invalidateCache() {
eventCache.start = null;
eventCache.end = null;
eventCache.events = [];
eventCache.start = null;
eventCache.end = null;
eventCache.events = [];
eventCache._fwdPending = false;
eventCache._bwdPending = false;
}
function _mergeEvents(newEvents) {
const seen = new Set(eventCache.events.map(e => e.id + '@@' + (e.url || '')));
for (const e of newEvents) {
const k = e.id + '@@' + (e.url || '');
if (!seen.has(k)) { seen.add(k); eventCache.events.push(e); }
}
}
// Fire-and-forget: extend the cache toward whichever edge the view is approaching
function prefetchIfNeeded(viewStart, viewEnd) {
if (!eventCache.start || !eventCache.end) return;
if (!eventCache._fwdPending && (eventCache.end - viewEnd) < PREFETCH_EDGE) {
eventCache._fwdPending = true;
const from = new Date(eventCache.end);
const to = new Date(eventCache.end.getTime() + PREFETCH_EXT);
api.get(`/caldav/events?start=${from.toISOString()}&end=${to.toISOString()}`)
.then(evs => { _mergeEvents(evs); eventCache.end = to; })
.catch(() => {})
.finally(() => { eventCache._fwdPending = false; });
}
if (!eventCache._bwdPending && (viewStart - eventCache.start) < PREFETCH_EDGE) {
eventCache._bwdPending = true;
const from = new Date(eventCache.start.getTime() - PREFETCH_EXT);
const to = new Date(eventCache.start);
api.get(`/caldav/events?start=${from.toISOString()}&end=${to.toISOString()}`)
.then(evs => { _mergeEvents(evs); eventCache.start = from; })
.catch(() => {})
.finally(() => { eventCache._bwdPending = false; });
}
}
// ── Data fetching ─────────────────────────────────────────
@@ -92,13 +134,13 @@ async function fetchAndRender(force = false) {
renderView();
updateTitle();
renderMiniCal();
prefetchIfNeeded(start, end); // extend cache in background if approaching an edge
return;
}
// Cache miss: fetch a wider window (±8 weeks) so subsequent navigation is instant
const BUF = 56 * 86400000; // 8 weeks in ms
const fetchStart = new Date(start.getTime() - BUF);
const fetchEnd = new Date(end.getTime() + BUF);
const fetchStart = new Date(start.getTime() - CACHE_BUF);
const fetchEnd = new Date(end.getTime() + CACHE_BUF);
showLoading();
try {