From adbd259a32478ef294699f7a83b21c38daa827f9 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 26 May 2026 09:37:24 +0100 Subject: [PATCH] =?UTF-8?q?music(perf):=20=E5=88=87=E6=AD=8C=E5=BB=B6?= =?UTF-8?q?=E8=BF=9F=E4=BF=AE=20=E2=80=94=20getAudioUrl=20=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=9F=AD=E8=B7=AF=20+=20SW=20install=20=E5=B9=B6?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 诊断:之前 loadPiece 链上加了 `audio.src = await getAudioUrl(...)`,await IDB 即使 cache disabled 也排队个 microtask;叠加 SW install 串行 23 个 fetch 让首次部署后明显卡。 修法: - getAudioUrl 改同步:内存 blob 命中 / cache 关 → 立返;启用 cache 时内存没 → 仍返网络 URL,后台 warm IDB 下次用 - audio.src = getAudioUrl(id) 不再 await,零等待 - SW install 改 cache.addAll 并发(HTTP/2 多路),失败回退串行 --- apps/music/frontend/src/lib/cache.js | 27 +++++++++++++++----- apps/music/frontend/src/sw.js | 16 +++++++----- apps/music/frontend/src/views/PlayerView.vue | 4 +-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/apps/music/frontend/src/lib/cache.js b/apps/music/frontend/src/lib/cache.js index dfdb1b9..e9dcf1e 100644 --- a/apps/music/frontend/src/lib/cache.js +++ b/apps/music/frontend/src/lib/cache.js @@ -124,14 +124,29 @@ export async function getCachedBlobUrl(store, attId) { return url } -export async function getAudioUrl(attId) { - const cached = await getCachedBlobUrl(STORE_AUDIO, attId) - return cached || attachmentUrl(attId) +// 短路:内存里已有 blob URL → 同步返回;未启用 cache → 直接网络 URL 不查 IDB; +// 只有启用 cache 且内存没 cache 命中才掏 IDB +export function getAudioUrl(attId) { + if (blobUrlCache.has(attId)) return blobUrlCache.get(attId) + if (!isCacheEnabled()) return attachmentUrl(attId) + // 启用了但内存没缓存:网络立返,后台尝试 IDB 命中后下次会用上 + warmCachedBlob(STORE_AUDIO, attId) + return attachmentUrl(attId) } -export async function getImageUrl(attId) { - const cached = await getCachedBlobUrl(STORE_IMAGE, attId) - return cached || attachmentUrl(attId) +export function getImageUrl(attId) { + if (blobUrlCache.has(attId)) return blobUrlCache.get(attId) + if (!isCacheEnabled()) return attachmentUrl(attId) + warmCachedBlob(STORE_IMAGE, attId) + return attachmentUrl(attId) +} + +function warmCachedBlob(store, attId) { + idbGet(store, attId).then((blob) => { + if (blob && !blobUrlCache.has(attId)) { + blobUrlCache.set(attId, URL.createObjectURL(blob)) + } + }).catch(() => {}) } // ---- 状态 ---- diff --git a/apps/music/frontend/src/sw.js b/apps/music/frontend/src/sw.js index 37f72bb..9a2e523 100644 --- a/apps/music/frontend/src/sw.js +++ b/apps/music/frontend/src/sw.js @@ -20,12 +20,16 @@ self.addEventListener('install', (event) => { event.waitUntil( (async () => { const cache = await caches.open(CACHE) - // 串行避免一次性请求过多 - for (const u of URLS) { - try { - const r = await fetch(u, { cache: 'reload' }) - if (r.ok) await cache.put(u, r) - } catch {} + // 并发 addAll,HTTP/2 多路复用,一次过;失败回退串行 + try { + await cache.addAll(URLS) + } catch { + for (const u of URLS) { + try { + const r = await fetch(u, { cache: 'reload' }) + if (r.ok) await cache.put(u, r) + } catch {} + } } await self.skipWaiting() })(), diff --git a/apps/music/frontend/src/views/PlayerView.vue b/apps/music/frontend/src/views/PlayerView.vue index 8aa9f98..b2b99c6 100644 --- a/apps/music/frontend/src/views/PlayerView.vue +++ b/apps/music/frontend/src/views/PlayerView.vue @@ -773,8 +773,8 @@ async function loadPiece(id) { await nextTick() const first = audioAttachments.value[0] if (first && audioEl.value) { - // 优先用 IDB 缓存的 blob URL,没有再走网络 - audioEl.value.src = await getAudioUrl(first.id) + // 优先用 IDB 缓存的 blob URL(cache 关时同步返回网络 URL,零延迟) + audioEl.value.src = getAudioUrl(first.id) if (wasPlaying) audioEl.value.play().catch(() => {}) } else if (audioEl.value) { audioEl.value.removeAttribute('src')