diff --git a/src/app/service/service_worker/script.ts b/src/app/service/service_worker/script.ts index e2cd92c01..baf968383 100644 --- a/src/app/service/service_worker/script.ts +++ b/src/app/service/service_worker/script.ts @@ -772,17 +772,51 @@ export class ScriptService { setTimeout(resolve, Math.round(MIN_DELAY + ((++i / n + Math.random()) / 2) * (MAX_DELAY - MIN_DELAY))) ); - return Promise.all( - (uuids as string[]).map(async (uuid, _idx) => { - const script = scripts[_idx]; - const res = - !script || script.uuid !== uuid || !checkScripts.includes(script) - ? false - : await this._checkUpdateAvailable(script, delayFn); - if (!res) return false; - return res; - }) - ); + const CHECK_UPDATE_TIMEOUT_MS = 300_000; // 5 分钟超时 + + const results = new Map< + string, + | false + | { + updateAvailable: true; + code: string; + metadata: Partial>; + } + >(); + + // 预初始化 Map 确保顺序 + for (const uuid of uuids as string[]) { + results.set(uuid, false); + } + + const abortController = new AbortController(); + let timeoutId: ReturnType; + + const timeoutPromise = new Promise((resolve) => { + timeoutId = setTimeout(() => { + abortController.abort(); + resolve(); + }, CHECK_UPDATE_TIMEOUT_MS); + }); + + await Promise.race([ + timeoutPromise, + Promise.allSettled( + (uuids as string[]).map(async (uuid, _idx) => { + const script = scripts[_idx]; + const res = + !script || script.uuid !== uuid || !checkScripts.includes(script) + ? false + : await this._checkUpdateAvailable(script, delayFn, abortController.signal); + if (!res) return false; + results.set(uuid, res); + return res; + }) + ).finally(() => { + clearTimeout(timeoutId); + }), + ]); + return [...results.values()]; } async _checkUpdateAvailable( @@ -792,7 +826,8 @@ export class ScriptService { checkUpdateUrl?: string; metadata: Partial>; }, - delayFn?: () => Promise + delayFn?: () => Promise, + signal?: AbortSignal ): Promise { const { uuid, name, checkUpdateUrl } = script; @@ -804,8 +839,12 @@ export class ScriptService { name, }); try { - if (delayFn) await delayFn(); - const code = await fetchScriptBody(checkUpdateUrl); + if (delayFn) { + if (signal?.aborted) return false; + await delayFn(); + } + if (signal?.aborted) return false; + const code = await fetchScriptBody(checkUpdateUrl, signal); const metadata = parseMetadata(code); if (!metadata) { logger.error("parse metadata failed"); diff --git a/src/pkg/utils/script.ts b/src/pkg/utils/script.ts index 76a5a5600..4f1ba4c57 100644 --- a/src/pkg/utils/script.ts +++ b/src/pkg/utils/script.ts @@ -46,8 +46,9 @@ export function parseMetadata(code: string): SCMetadata | null { } // 从网址取得脚本代码 -export async function fetchScriptBody(url: string): Promise { +export async function fetchScriptBody(url: string, signal?: AbortSignal): Promise { const resp = await fetch(url, { + signal, headers: { "Cache-Control": "no-cache", },