stackchain-dashboard/frontend/context-poller.js
timmy fedddb246d
All checks were successful
CI / lint (pull_request) Successful in 25s
CI / build-frontend (pull_request) Successful in 5s
perf: skip unchanged live snapshot sections (#285)
2026-08-08 09:35:48 +00:00

81 lines
1.8 KiB
JavaScript

function createContextPoller({
fetchContext,
onSnapshot,
onError,
isHidden = () => false,
setTimer = setTimeout,
clearTimer = clearTimeout,
intervalMs = 8000,
}) {
let inFlight = null;
let timer = null;
let stopped = false;
let revisions = {};
let retainedSnapshot = null;
function cancelTimer() {
if (timer !== null) clearTimer(timer);
timer = null;
}
function schedule() {
cancelTimer();
if (stopped || isHidden()) return;
timer = setTimer(() => {
timer = null;
refresh();
}, intervalMs);
}
function refresh() {
if (stopped || isHidden()) return Promise.resolve(null);
if (inFlight) return inFlight;
let request;
try {
request = fetchContext({ ...revisions });
} catch (error) {
request = Promise.reject(error);
}
inFlight = Promise.resolve(request)
.then((snapshot) => {
const changedSections = ['context', 'events', 'notifications'].filter(
(section) => Object.prototype.hasOwnProperty.call(snapshot, section)
);
retainedSnapshot = retainedSnapshot ? { ...retainedSnapshot, ...snapshot } : { ...snapshot };
revisions = { ...revisions, ...(snapshot.revisions || {}) };
onSnapshot(retainedSnapshot, changedSections);
return retainedSnapshot;
})
.catch((error) => {
onError(error);
return null;
})
.finally(() => {
inFlight = null;
schedule();
});
return inFlight;
}
function setVisible(visible) {
cancelTimer();
if (!visible) return Promise.resolve(null);
return refresh();
}
return {
start: refresh,
refresh,
setVisible,
stop() {
stopped = true;
cancelTimer();
},
};
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = createContextPoller;
}