修复图表观测缓存阻塞详情加载
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
mergeHourlyWithLiveObservations,
|
mergeHourlyWithLiveObservations,
|
||||||
mergePatchIntoHourly,
|
mergePatchIntoHourly,
|
||||||
mergeRowObservationIntoHourly,
|
mergeRowObservationIntoHourly,
|
||||||
|
readCachedHourlyForInitialRow,
|
||||||
rememberHourlyDetailSnapshot,
|
rememberHourlyDetailSnapshot,
|
||||||
selectInitialHourlyForRowChange,
|
selectInitialHourlyForRowChange,
|
||||||
seedHourlyForecastFromRow,
|
seedHourlyForecastFromRow,
|
||||||
@@ -223,6 +224,28 @@ export function runTests() {
|
|||||||
"chart should use the current scan row local date when cached detail localDate is older so today's model curve is drawn through 23:00",
|
"chart should use the current scan row local date when cached detail localDate is older so today's model curve is drawn through 23:00",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_hourlyCache.clear();
|
||||||
|
_hourlyCache.set("madrid:10m", {
|
||||||
|
ts: Date.now(),
|
||||||
|
data: {
|
||||||
|
localDate: "2026-06-16",
|
||||||
|
localTime: "15:46",
|
||||||
|
times: [],
|
||||||
|
temps: [],
|
||||||
|
airportPrimary: {
|
||||||
|
temp: 28.8,
|
||||||
|
obs_time: "2026-06-16T13:46:00Z",
|
||||||
|
},
|
||||||
|
airportPrimaryTodayObs: [["2026-06-16T13:46:00Z", 28.8]],
|
||||||
|
} as any,
|
||||||
|
});
|
||||||
|
const observationOnlyInitialCache = readCachedHourlyForInitialRow("madrid", "10m");
|
||||||
|
assert(
|
||||||
|
observationOnlyInitialCache === null,
|
||||||
|
"observation-only hourly cache entries must not block loading the full city detail payload",
|
||||||
|
);
|
||||||
|
_hourlyCache.clear();
|
||||||
|
|
||||||
const correctedDetailChart = getTemperatureChartData(
|
const correctedDetailChart = getTemperatureChartData(
|
||||||
{
|
{
|
||||||
name: "shanghai",
|
name: "shanghai",
|
||||||
|
|||||||
@@ -441,9 +441,13 @@ function isRetainedHourlyCacheEntry(
|
|||||||
return Number.isFinite(age) && age >= 0 && age < maxAgeMs;
|
return Number.isFinite(age) && age >= 0 && age < maxAgeMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isUsableHourlyDetailCacheEntry(entry: HourlyCacheEntry | null | undefined) {
|
||||||
|
return Boolean(entry?.data && hasFullHourlyDetailPayload(entry.data));
|
||||||
|
}
|
||||||
|
|
||||||
function pruneHourlyCache() {
|
function pruneHourlyCache() {
|
||||||
for (const [key, entry] of _hourlyCache.entries()) {
|
for (const [key, entry] of _hourlyCache.entries()) {
|
||||||
if (!isRetainedHourlyCacheEntry(entry, HOURLY_CACHE_STALE_TTL_MS)) {
|
if (!isUsableHourlyDetailCacheEntry(entry) || !isRetainedHourlyCacheEntry(entry, HOURLY_CACHE_STALE_TTL_MS)) {
|
||||||
_hourlyCache.delete(key);
|
_hourlyCache.delete(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,7 +463,7 @@ function pruneHourlyCache() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function rememberMemoryHourlyCacheEntry(cacheKey: string, entry: HourlyCacheEntry) {
|
function rememberMemoryHourlyCacheEntry(cacheKey: string, entry: HourlyCacheEntry) {
|
||||||
if (!cacheKey || !entry?.data) return;
|
if (!cacheKey || !isUsableHourlyDetailCacheEntry(entry)) return;
|
||||||
_hourlyCache.set(cacheKey, entry);
|
_hourlyCache.set(cacheKey, entry);
|
||||||
pruneHourlyCache();
|
pruneHourlyCache();
|
||||||
}
|
}
|
||||||
@@ -476,7 +480,11 @@ function readSessionCache(
|
|||||||
const maxAgeMs = options.allowStale
|
const maxAgeMs = options.allowStale
|
||||||
? HOURLY_CACHE_STALE_TTL_MS
|
? HOURLY_CACHE_STALE_TTL_MS
|
||||||
: options.maxAgeMs ?? SESSION_CACHE_TTL_MS;
|
: options.maxAgeMs ?? SESSION_CACHE_TTL_MS;
|
||||||
if (item && item.ts && isRetainedHourlyCacheEntry(item, maxAgeMs)) {
|
if (!item || !item.ts || !isUsableHourlyDetailCacheEntry(item) || !isRetainedHourlyCacheEntry(item, HOURLY_CACHE_STALE_TTL_MS)) {
|
||||||
|
sessionStorage.removeItem(`${SESSION_CACHE_PREFIX}${city}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (isRetainedHourlyCacheEntry(item, maxAgeMs)) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
@@ -488,10 +496,14 @@ function readHourlyCacheEntry(
|
|||||||
options: { allowStale?: boolean; maxAgeMs?: number } = {},
|
options: { allowStale?: boolean; maxAgeMs?: number } = {},
|
||||||
): HourlyCacheEntry | null {
|
): HourlyCacheEntry | null {
|
||||||
const cached = _hourlyCache.get(cacheKey);
|
const cached = _hourlyCache.get(cacheKey);
|
||||||
if (cached && (options.allowStale ? isRetainedHourlyCacheEntry(cached) : isFreshHourlyCacheEntry(cached, options.maxAgeMs))) {
|
if (
|
||||||
|
cached &&
|
||||||
|
isUsableHourlyDetailCacheEntry(cached) &&
|
||||||
|
(options.allowStale ? isRetainedHourlyCacheEntry(cached) : isFreshHourlyCacheEntry(cached, options.maxAgeMs))
|
||||||
|
) {
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
if (cached && !isRetainedHourlyCacheEntry(cached)) {
|
if (cached && (!isUsableHourlyDetailCacheEntry(cached) || !isRetainedHourlyCacheEntry(cached))) {
|
||||||
_hourlyCache.delete(cacheKey);
|
_hourlyCache.delete(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,10 +521,14 @@ function readHourlyCacheSnapshot(
|
|||||||
options: { allowStale?: boolean; maxAgeMs?: number } = {},
|
options: { allowStale?: boolean; maxAgeMs?: number } = {},
|
||||||
): HourlyDetailSnapshotEntry | null {
|
): HourlyDetailSnapshotEntry | null {
|
||||||
const cached = _hourlyCache.get(cacheKey);
|
const cached = _hourlyCache.get(cacheKey);
|
||||||
if (cached && (options.allowStale ? isRetainedHourlyCacheEntry(cached) : isFreshHourlyCacheEntry(cached, options.maxAgeMs))) {
|
if (
|
||||||
|
cached &&
|
||||||
|
isUsableHourlyDetailCacheEntry(cached) &&
|
||||||
|
(options.allowStale ? isRetainedHourlyCacheEntry(cached) : isFreshHourlyCacheEntry(cached, options.maxAgeMs))
|
||||||
|
) {
|
||||||
return { ...cached, source: "memory_cache" };
|
return { ...cached, source: "memory_cache" };
|
||||||
}
|
}
|
||||||
if (cached && !isRetainedHourlyCacheEntry(cached)) {
|
if (cached && (!isUsableHourlyDetailCacheEntry(cached) || !isRetainedHourlyCacheEntry(cached))) {
|
||||||
_hourlyCache.delete(cacheKey);
|
_hourlyCache.delete(cacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user