Remove dashboard prewarm requests
This commit is contained in:
@@ -5,7 +5,7 @@ import clsx from "clsx";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { ForecastTable } from "@/components/dashboard/PanelSections";
|
||||
import { preloadChartJs, useChart } from "@/hooks/useChart";
|
||||
import { useChart } from "@/hooks/useChart";
|
||||
import { useDashboardStore } from "@/hooks/useDashboardStore";
|
||||
import { useI18n } from "@/hooks/useI18n";
|
||||
import { getOfficialSourceLinks } from "@/lib/dashboard-official-sources";
|
||||
@@ -360,12 +360,6 @@ export function DetailPanel() {
|
||||
: `${t("detail.todayAnalysis")} (Pro)`
|
||||
}
|
||||
onClick={() => handleFeatureAccess("today")}
|
||||
onFocus={() => {
|
||||
void preloadChartJs();
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
void preloadChartJs();
|
||||
}}
|
||||
disabled={!store.selectedCity}
|
||||
>
|
||||
{isPro
|
||||
@@ -379,12 +373,6 @@ export function DetailPanel() {
|
||||
isPro ? t("detail.history") : `${t("detail.history")} (Pro)`
|
||||
}
|
||||
onClick={() => handleFeatureAccess("history")}
|
||||
onFocus={() => {
|
||||
void preloadChartJs();
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
void preloadChartJs();
|
||||
}}
|
||||
disabled={!store.selectedCity}
|
||||
>
|
||||
{isPro ? t("detail.history") : `${t("detail.history")} · Pro`}
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
DashboardStoreProvider,
|
||||
useDashboardStore,
|
||||
} from "@/hooks/useDashboardStore";
|
||||
import { preloadChartJs } from "@/hooks/useChart";
|
||||
import { I18nProvider, useI18n } from "@/hooks/useI18n";
|
||||
import { CitySidebar } from "@/components/dashboard/CitySidebar";
|
||||
import { DetailPanel } from "@/components/dashboard/DetailPanel";
|
||||
@@ -82,42 +81,6 @@ function DashboardScreen() {
|
||||
};
|
||||
}, [store]);
|
||||
|
||||
useEffect(() => {
|
||||
const browserWindow = window as Window & {
|
||||
requestIdleCallback?: (
|
||||
cb: IdleRequestCallback,
|
||||
options?: IdleRequestOptions,
|
||||
) => number;
|
||||
cancelIdleCallback?: (handle: number) => void;
|
||||
};
|
||||
if (typeof browserWindow.requestIdleCallback === "function") {
|
||||
const handle = browserWindow.requestIdleCallback(() => {
|
||||
void loadHistoryModal();
|
||||
void loadFutureForecastModal();
|
||||
}, { timeout: 1200 });
|
||||
return () => {
|
||||
if (typeof browserWindow.cancelIdleCallback === "function") {
|
||||
browserWindow.cancelIdleCallback(handle);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const timeoutId = window.setTimeout(() => {
|
||||
void loadHistoryModal();
|
||||
void loadFutureForecastModal();
|
||||
}, 500);
|
||||
return () => {
|
||||
window.clearTimeout(timeoutId);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!store.selectedCity) return;
|
||||
void preloadChartJs();
|
||||
void loadHistoryModal();
|
||||
void loadFutureForecastModal();
|
||||
}, [store.selectedCity]);
|
||||
|
||||
// Avoid full-page flashing on initial load; only show this overlay for manual refresh.
|
||||
const showLoading =
|
||||
store.loadingState.cities ||
|
||||
|
||||
@@ -101,38 +101,6 @@ function getMarketScanCacheKey(cityName: string, targetDate?: string | null) {
|
||||
|
||||
const SELECTED_CITY_STORAGE_KEY = "polyWeather_selected_city_v1";
|
||||
const BACKGROUND_SUMMARY_REFRESH_MS = 30_000;
|
||||
const EAGER_CITY_SUMMARIES_DISABLED =
|
||||
process.env.NEXT_PUBLIC_POLYWEATHER_DISABLE_EAGER_SUMMARIES === "true";
|
||||
const EAGER_SUMMARY_PRIORITY_CONCURRENCY = 3;
|
||||
const EAGER_SUMMARY_BACKGROUND_CONCURRENCY = 2;
|
||||
const EAGER_SUMMARY_BACKGROUND_IDLE_TIMEOUT_MS = 1200;
|
||||
const EAGER_SUMMARY_PRIORITY_CITY_ORDER = [
|
||||
"hong kong",
|
||||
"taipei",
|
||||
"shanghai",
|
||||
"beijing",
|
||||
"wuhan",
|
||||
"shenzhen",
|
||||
"chengdu",
|
||||
"chongqing",
|
||||
"seoul",
|
||||
"busan",
|
||||
"tokyo",
|
||||
"singapore",
|
||||
"kuala lumpur",
|
||||
"jakarta",
|
||||
"tel aviv",
|
||||
"jeddah",
|
||||
"istanbul",
|
||||
"moscow",
|
||||
"helsinki",
|
||||
"warsaw",
|
||||
"amsterdam",
|
||||
"london",
|
||||
"paris",
|
||||
"milan",
|
||||
"madrid",
|
||||
] as const;
|
||||
type CityDetailDepth = "panel" | "market" | "nearby" | "full";
|
||||
|
||||
function countAvailableModels(
|
||||
@@ -291,57 +259,6 @@ function mergeCityDetail(
|
||||
};
|
||||
}
|
||||
|
||||
function getStoredSelectedCityName(cities: CityListItem[]) {
|
||||
if (typeof window === "undefined") return null;
|
||||
const stored = String(
|
||||
window.localStorage.getItem(SELECTED_CITY_STORAGE_KEY) || "",
|
||||
)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!stored) return null;
|
||||
if (!cities.some((city) => city.name === stored)) return null;
|
||||
return stored;
|
||||
}
|
||||
|
||||
function getPriorityPreloadCities(cities: CityListItem[]) {
|
||||
const citySet = new Set(cities.map((city) => city.name));
|
||||
return EAGER_SUMMARY_PRIORITY_CITY_ORDER.filter((cityName) =>
|
||||
citySet.has(cityName)
|
||||
);
|
||||
}
|
||||
|
||||
function scheduleWhenBrowserIdle(callback: () => void) {
|
||||
if (typeof window === "undefined") {
|
||||
callback();
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const browserWindow = window as Window & {
|
||||
requestIdleCallback?: (
|
||||
cb: IdleRequestCallback,
|
||||
options?: IdleRequestOptions,
|
||||
) => number;
|
||||
cancelIdleCallback?: (handle: number) => void;
|
||||
};
|
||||
|
||||
if (typeof browserWindow.requestIdleCallback === "function") {
|
||||
const handle = browserWindow.requestIdleCallback(
|
||||
() => callback(),
|
||||
{ timeout: EAGER_SUMMARY_BACKGROUND_IDLE_TIMEOUT_MS },
|
||||
);
|
||||
return () => {
|
||||
if (typeof browserWindow.cancelIdleCallback === "function") {
|
||||
browserWindow.cancelIdleCallback(handle);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const timeoutId = window.setTimeout(callback, 400);
|
||||
return () => {
|
||||
window.clearTimeout(timeoutId);
|
||||
};
|
||||
}
|
||||
|
||||
function toHistoryMeta(payload: HistoryPayload): HistoryPayloadMeta {
|
||||
const history = Array.isArray(payload.history) ? payload.history : [];
|
||||
const previewCount = Number(payload.preview_count || history.length || 0);
|
||||
@@ -844,75 +761,6 @@ export function DashboardStoreProvider({
|
||||
proAccess.userId,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (EAGER_CITY_SUMMARIES_DISABLED) return;
|
||||
if (!cities.length) return;
|
||||
if (loadingState.refresh) return;
|
||||
|
||||
const priorityQueue: string[] = [];
|
||||
const backgroundQueue: string[] = [];
|
||||
const queued = new Set<string>();
|
||||
const enqueue = (cityName: string | null, queue: string[]) => {
|
||||
if (!cityName || queued.has(cityName) || citySummariesRef.current[cityName]) {
|
||||
return;
|
||||
}
|
||||
queued.add(cityName);
|
||||
queue.push(cityName);
|
||||
};
|
||||
|
||||
enqueue(getStoredSelectedCityName(cities), priorityQueue);
|
||||
getPriorityPreloadCities(cities).forEach((cityName) => {
|
||||
enqueue(cityName, priorityQueue);
|
||||
});
|
||||
cities.forEach((city) => {
|
||||
enqueue(city.name, backgroundQueue);
|
||||
});
|
||||
|
||||
if (!priorityQueue.length && !backgroundQueue.length) return;
|
||||
|
||||
let active = true;
|
||||
let cancelIdleSchedule = () => {};
|
||||
const runQueue = async (queue: string[], concurrency: number) => {
|
||||
if (!queue.length) return;
|
||||
let cursor = 0;
|
||||
const worker = async () => {
|
||||
while (active && cursor < queue.length) {
|
||||
const cityName = queue[cursor];
|
||||
cursor += 1;
|
||||
if (citySummariesRef.current[cityName]) continue;
|
||||
|
||||
try {
|
||||
await ensureCitySummary(cityName);
|
||||
} catch {}
|
||||
}
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
Array.from({ length: Math.min(concurrency, queue.length) }, () =>
|
||||
worker()
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
void (async () => {
|
||||
await runQueue(priorityQueue, EAGER_SUMMARY_PRIORITY_CONCURRENCY);
|
||||
if (!active) return;
|
||||
if (isMapInteracting) return;
|
||||
cancelIdleSchedule = scheduleWhenBrowserIdle(() => {
|
||||
if (!active || isMapInteracting) return;
|
||||
void runQueue(
|
||||
backgroundQueue,
|
||||
EAGER_SUMMARY_BACKGROUND_CONCURRENCY,
|
||||
);
|
||||
});
|
||||
})();
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
cancelIdleSchedule();
|
||||
};
|
||||
}, [cities, isMapInteracting, loadingState.refresh]);
|
||||
|
||||
const selectCity = async (cityName: string) => {
|
||||
setSelectedCity(cityName);
|
||||
setIsPanelOpen(true);
|
||||
@@ -961,16 +809,6 @@ export function DashboardStoreProvider({
|
||||
.then((detail) => {
|
||||
if (selectedCityRef.current !== cityName) return;
|
||||
setSelectedForecastDate(detail.local_date);
|
||||
if (access.authenticated && access.subscriptionActive) {
|
||||
void ensureCityDetail(cityName, false, "market").catch(() => {});
|
||||
// 预热市场数据,不做 await 阻塞,后台静默拉取
|
||||
void ensureCityMarketScan(
|
||||
cityName,
|
||||
false,
|
||||
null,
|
||||
detail.local_date,
|
||||
).catch(() => {});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (selectedCityRef.current !== cityName) return;
|
||||
@@ -1002,8 +840,12 @@ export function DashboardStoreProvider({
|
||||
)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!stored) return;
|
||||
if (!cities.some((city) => city.name === stored)) return;
|
||||
if (!stored) {
|
||||
return;
|
||||
}
|
||||
if (!cities.some((city) => city.name === stored)) {
|
||||
return;
|
||||
}
|
||||
void selectCity(stored);
|
||||
}, [cities, selectedCity, selectCity]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user