From 0858797405a9dafa18e2dcca3d6a584f222d104d Mon Sep 17 00:00:00 2001 From: shenmo Date: Tue, 14 Jul 2026 14:08:17 +0800 Subject: [PATCH] =?UTF-8?q?perf(App.vue):=20=E4=BF=AE=E5=A4=8D=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E5=88=97=E8=A1=A8N+1=E8=AF=B7=E6=B1=82=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=8C=E4=BC=98=E5=8C=96=E5=8A=A0=E8=BD=BD=E6=80=A7?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 直接使用接口返回的列表数据构建应用对象,不再为每个应用单独请求app.json,应用详情将在用户点击时按需获取 --- src/App.vue | 65 +++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/App.vue b/src/App.vue index 9c2c6f69..02fc5bd2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1201,42 +1201,43 @@ const loadHomeListApps = async (entryId: string) => { const path = `/${finalArch}${jsonUrl}`; const rawApps = (await fetchWithRetry[]>(path)) || []; - const apps = await Promise.all( - rawApps.map(async (a) => { - const category = a.Category || a.category || "unknown"; - const pkgname = a.Pkgname || a.pkgname || ""; + // 直接使用列表数据构建 App 对象,避免为每个应用单独请求 app.json(N+1 问题) + // 应用详情会在用户点击时通过 fetchAppFromStore 按需获取 + const apps = rawApps.map((a) => { + const category = a.Category || a.category || "unknown"; - // 复用首页逻辑:从仓库获取完整应用信息 + let img_urls: string[] = []; + const rawImgUrls = a.img_urls; + if (typeof rawImgUrls === "string") { try { - const realAppUrl = `/${finalArch}/${category}/${pkgname}/app.json`; - const realApp = await fetchWithRetry(realAppUrl); - return normalizeAppJson(realApp, category, mode); - } catch (e) { - console.warn(`Failed to fetch app.json for ${pkgname}`, e); + img_urls = JSON.parse(rawImgUrls); + } catch { + img_urls = []; } + } else if (Array.isArray(rawImgUrls)) { + img_urls = rawImgUrls; + } - // 回退:使用列表中的基本信息构建 App 对象 - return { - name: a.Name || a.name || pkgname || "", - pkgname, - version: a.Version || "", - filename: a.Filename || a.filename || "", - category, - more: a.More || a.more || "", - torrent_address: "", - author: "", - contributor: "", - website: "", - update: "", - size: "", - tags: "", - img_urls: [], - icons: "", - origin: mode, - currentStatus: "not-installed" as const, - } as App; - }), - ); + return { + name: a.Name || a.name || a.Pkgname || a.pkgname || "", + pkgname: a.Pkgname || a.pkgname || "", + version: a.Version || "", + filename: a.Filename || a.filename || "", + torrent_address: a.Torrent_address || "", + author: a.Author || "", + contributor: a.Contributor || "", + website: a.Website || "", + update: a.Update || "", + size: a.Size || "", + more: a.More || a.more || "", + tags: a.Tags || "", + img_urls, + icons: a.icons || "", + category, + origin: mode, + currentStatus: "not-installed" as const, + } as App; + }); loadedApps.push(...apps); } catch (e) { logger.warn(`加载首页列表 ${entryId} (${mode}) 失败: ${e}`);