fix: 清理前端异步请求生命周期

- 页面卸载和弹窗关闭时终止 SSE

- 为版本检查增加超时、中止与重复请求保护
This commit is contained in:
2026-07-27 19:41:48 +08:00
parent a904f63ec8
commit 908eb5583d
6 changed files with 125 additions and 30 deletions

View File

@@ -21,6 +21,8 @@ const props = withDefaults(defineProps<Props>(), {
let isCheckingUpdates = false;
let resumeCheckFrame: number | undefined;
let versionCheckController: AbortController | null = null;
const VERSION_CHECK_TIMEOUT_MS = 10_000;
const currentVersionTag = ref('');
const lastVersionTag = ref('');
const timer = ref<ReturnType<typeof setInterval>>();
@@ -37,6 +39,12 @@ const [UpdateNoticeModal, modalApi] = useEasyFlowModal({
});
async function getVersionTag() {
const controller = new AbortController();
versionCheckController = controller;
const timeout = setTimeout(
() => controller.abort(),
VERSION_CHECK_TIMEOUT_MS,
);
try {
if (
location.hostname === 'localhost' ||
@@ -48,14 +56,22 @@ async function getVersionTag() {
cache: 'no-cache',
method: 'HEAD',
redirect: 'manual',
signal: controller.signal,
});
return (
response.headers.get('etag') || response.headers.get('last-modified')
);
} catch {
console.error('Failed to fetch version tag');
} catch (error) {
if (!controller.signal.aborted) {
console.error('Failed to fetch version tag', error);
}
return null;
} finally {
clearTimeout(timeout);
if (versionCheckController === controller) {
versionCheckController = null;
}
}
}
@@ -72,10 +88,21 @@ async function checkForUpdates() {
}
if (lastVersionTag.value !== versionTag && versionTag) {
clearInterval(timer.value);
stop();
handleNotice(versionTag);
}
}
async function runUpdateCheck() {
if (isCheckingUpdates) return;
isCheckingUpdates = true;
try {
await checkForUpdates();
} finally {
isCheckingUpdates = false;
}
}
function handleNotice(versionTag: string) {
currentVersionTag.value = versionTag;
modalApi.open();
@@ -89,7 +116,7 @@ function start() {
// 每 checkUpdatesInterval(默认值为1) 分钟检查一次
timer.value = setInterval(
checkForUpdates,
() => void runUpdateCheck(),
props.checkUpdatesInterval * 60 * 1000,
);
}
@@ -108,13 +135,11 @@ function scheduleResumeCheck() {
resumeCheckFrame = requestAnimationFrame(() => {
resumeCheckFrame = requestAnimationFrame(() => {
resumeCheckFrame = undefined;
if (document.hidden || isCheckingUpdates) {
return;
}
isCheckingUpdates = true;
checkForUpdates().finally(() => {
isCheckingUpdates = false;
start();
if (document.hidden) return;
runUpdateCheck().finally(() => {
if (!document.hidden) {
start();
}
});
});
});
@@ -130,11 +155,12 @@ function handleVisibilitychange() {
}
function stop() {
if (timer.value === undefined) {
return;
if (timer.value !== undefined) {
clearInterval(timer.value);
timer.value = undefined;
}
clearInterval(timer.value);
timer.value = undefined;
versionCheckController?.abort();
versionCheckController = null;
}
onMounted(() => {