Improve loading from sections with local caches

This commit is contained in:
HighImKevin
2026-09-25 05:03:31 -04:00
parent 356da23ce1
commit e4ddc9e645
6 changed files with 213 additions and 115 deletions
+47 -12
View File
@@ -385,7 +385,7 @@
* @param {Object} options - Cache options
* @param {boolean} options.useCache - Whether to return cached data first (default: false)
* @param {number} options.ttl - Cache time to live in milliseconds (default: 300000)
* @returns {Promise<Object>|Object} - If useCache is true, returns { data, dataPromise, isStalePromise }. Otherwise returns Promise<data>.
* @returns {Object|Promise<Object>} - If useCache is true, returns progressive stub { data, ensureData, isStalePromise } synchronously. Otherwise returns Promise<data>.
*/
getQuery: function(url, options = {}) {
ensureApiClient();
@@ -616,14 +616,49 @@
return result.ensureData();
}
});
return (async () => {
// Initial check for cached data
const entry = await cachePromise;
result.data = entry ? entry.payload : null;
result.isStale = forceRefresh || !entry || (Date.now() - entry.timestamp > ttl);
return result;
})();
// Sync stub: do not await IndexedDB before return (home first paint).
// cachePromise / isStalePromise hydrate result.data in the background.
// Thenable waits for hydrate but must NOT fulfill with `result` itself
// (Promise assimilation would recurse on result.then forever).
result.data = { Items: [] };
result.isStale = true;
const readyPromise = cachePromise.then((entry) => {
if (entry) {
result.data = entry.payload;
result.isStale = forceRefresh || (Date.now() - entry.timestamp > ttl);
} else {
// Cache miss: clear placeholder so data?.Items cannot fake a hit
result.data = null;
result.isStale = true;
}
}).catch(() => {
result.data = null;
result.isStale = true;
});
function toSettledView() {
return {
data: result.data,
isStale: result.isStale,
isStalePromise: result.isStalePromise,
ensureData: result.ensureData,
get dataPromise() {
return result.ensureData();
}
};
}
result.then = function (onFulfilled, onRejected) {
return readyPromise.then(
() => (typeof onFulfilled === 'function' ? onFulfilled(toSettledView()) : toSettledView()),
onRejected
);
};
result.catch = function (onRejected) {
return result.then(undefined, onRejected);
};
return result;
},
invalidateCache: function(url) {
@@ -721,7 +756,7 @@
throw new Error('Invalid watchlist query URL');
}
const queryResult = await this.getQuery(url, {
const queryResult = this.getQuery(url, {
useCache: true,
ttl,
forceRefresh
@@ -744,8 +779,8 @@
};
const result = {
data: normalize(queryResult.data),
isStale: queryResult.isStale === true,
data: { Items: [] },
isStale: true,
isStalePromise: queryResult.isStalePromise || Promise.resolve(false),
ensureData,
urls: [url]