diff --git a/src/layouts/PublicLayout.tsx b/src/layouts/PublicLayout.tsx index 2eff651..684908a 100644 --- a/src/layouts/PublicLayout.tsx +++ b/src/layouts/PublicLayout.tsx @@ -294,29 +294,41 @@ export function PublicLayout() { // Current page name shown in the header brand slot (falls back to the brand). const pageTitle = usePageTitle(); - // Warm "全部资料" and "热门资料" in the background (when idle) so tapping them - // shows content immediately instead of loading on arrival. + // Warm the common stream views (全部资料 / 热门资料 / 最新) in the background so + // tapping them shows content immediately. Run one at a time, spaced out and + // only while idle, so prefetching never competes with the current page or + // janks low-end phones. Prefetch is JSON-only (no images). useEffect(() => { - const run = () => { - const base = { - scope: { kind: "all" as const }, - type: "all", - q: "", - lang, - }; - prefetchPostStream({ ...base, sort: "" }); - prefetchPostStream({ ...base, sort: "popular" }); - }; + const base = { scope: { kind: "all" as const }, type: "all", q: "", lang }; + const jobs = [ + () => prefetchPostStream({ ...base, sort: "" }), + () => prefetchPostStream({ ...base, sort: "popular" }), + () => prefetchPostStream({ ...base, sort: "latest" }), + ]; const ric = window as typeof window & { requestIdleCallback?: (cb: () => void) => number; cancelIdleCallback?: (id: number) => void; }; - if (ric.requestIdleCallback) { - const id = ric.requestIdleCallback(run); - return () => ric.cancelIdleCallback?.(id); - } - const id = window.setTimeout(run, 600); - return () => window.clearTimeout(id); + + let i = 0; + let stepTimer = 0; + let idleId = 0; + const runNext = () => { + if (i >= jobs.length) return; + jobs[i++](); + stepTimer = window.setTimeout(schedule, 400); // space requests apart + }; + const schedule = () => { + if (ric.requestIdleCallback) idleId = ric.requestIdleCallback(runNext); + else stepTimer = window.setTimeout(runNext, 200); + }; + + const startTimer = window.setTimeout(schedule, 600); + return () => { + window.clearTimeout(startTimer); + window.clearTimeout(stepTimer); + if (idleId) ric.cancelIdleCallback?.(idleId); + }; }, [lang]); const popularHref = "/browse?sort=popular";