Skip to content

首页首屏性能问题:启动后约十秒整页空白且无提示(含首页全前端演进方案) #494

Description

@1w1w11w1

首页首屏性能问题:启动后约十秒整页空白且无任何提示(含「首页全前端」演进方案)

概述

用户在前端调起后,首页从「全空」到「活动信息等板块正确加载」之间约有 10 秒空白,期间空白区域完全无加载提示;切换页面同样是全空、无提示,只能等待。该等待还与本地网络状态相关,开启代理/弱网时明显更久。

本 issue 记录实测数据、根因定位,以及一个按「首页全前端」方向拟定的演进方案。

可观察现象

  1. 应用启动后约 10 秒内,主页(以及此期间切换到的其他页面)为空白,无骨架/加载/错误提示。
  2. 等待结束后活动卡、方舟关卡、代理概况一次性出现。
  3. 延迟随网络状态(代理开启程度、弱网)明显放大。

实测数据(冷启动探针)

POST /api/info/get/overview 在启动后逐秒采样:

时间点 overview setting scripts notice
t≈2.7s(首次) 17176ms 15ms 101ms 7ms
t≈21s+ 39ms 12ms 67ms 5ms

后端日志显示:Uvicorn running(t≈18.6s)后,到 t≈35.7s 之间 事件循环没有任何一条日志,活动服务自己发起的后台 TCP 连接也要排到 t≈35.7s 才开始。即:Uvicorn 已可接收连接,但后端事件循环被冻结了约 17 秒,这段时间内所有 API 请求(不限于 overview)都排队等待。前端此时已连上主 WebSocket、已渲染,但所有数据请求都排在冻结窗口之后——这正是「主页全空、切页也全空」的来源。

该冻结与网络无关(关闭 MCP、关闭所有远端依赖后复测仍约 17 秒),属于后端后台初始化自身的同步/CPU 占用阻塞事件循环。

另外注意:setting/scripts/notice 在同一窗口内仅几十毫秒,说明首屏慢不是这些页面慢,而是全部请求共同被冻结窗口延迟

根因定位

「十秒空白」由两个相互独立的根因叠加:

根因 A — 后端事件循环冻结(约 17s)
main.py 后台初始化段(clean_maafw_agent_venvs → MaaFW 适配器导入 → ArknightWin32Toolkit.initMainTimer.start)在事件循环内执行耗时初始化,逐项实测各模块导入约 1–2s,但叠加 + 进程内行为合计把事件循环卡住约 17s,期间 overview/scripts/setting 等全部接口静默排队。

根因 B — 前端引导期门禁

  • Home.vue:49 内容区以 layoutReady && !isBootstrapping 为条件,引导期间直接不渲染内容卡。
  • 路由守卫在 isBootstrapping 为真时把一切非 /home 导航强制打回 /home
  • 因此引导期内既无内容、又不允许跳转,表现为「全空 + 切页也全空 + 无提示」。

演进方向:首页全前端

背景:首页数据当前 100% 依赖后端聚合接口 POST /api/info/get/overviewapp/api/info.py:270),由 asyncio.gather 聚合 7 个第三方活动源 + 方舟关卡 + 代理历史后一次性返回;前端(useHomeOverview.ts:66) 只是渲染壳 + 轮询兜底。

拟定方向为「首页全前端」:让活动卡在浏览器端直接请求各第三方源,逐卡独立超时/缓存/失败,从而不再受后端事件循环约束。

可行性:CORS 已实测全部放行

Origin: http://localhost:5173 + cors 模式探测各源响应头:

卡片 来源 host Access-Control-Allow-Origin
星穹 / 原神 / 绝区零 / 鸣潮 / 异环(5 卡) starrailassistant.top *
重返未来 api.1999.fan *
终末地 data.akedata.wiki *

* 对开发环境 http://localhost 与生产版 file://(null origin,无凭证)均成立,浏览器直连技术上可行。

关键:全前端并非字面全前端

  • 方舟关卡:依赖后端关卡缓存 + 硬编码资源表(RESOURCE_STAGE_INFO / RESOURCE_STAGE_DATE_TEXT 等)。
  • 代理概况:读取本机 history/ 目录(search_history / merge_statistic_info),属本地数据。

这两张卡第三方源给不了,必须留后端。因此目标形态是「7 张活动卡走前端 + 方舟/代理 2 张卡留后端」,后端聚合接口相应瘦身。

各卡成本差异

卡片 成本
SRA 5 卡(sr/ys/zzz/ww/nte) 最低:同 host 同格式,一个解析器复用
重返未来 中:单 JSON(api.1999.fan/.../cn.json
终末地 高:需拉 manifest.json + 6 张 GameTable JSON,再做 i18n 文本解析 + 时区换算合并

分阶段演进方案

  • Phase 0 — 前端引导期解卡(最便宜,收益直观):去掉 !isBootstrapping 对内容卡的硬性隐藏,改为卡片各自显示骨架/加载态;引导期放行导航,各页自处理 loading。消除「全空且无提示 + 切页全空」。
  • Phase 1 — 后端事件循环解冻(全前端与否都必须做):将 main.py 后台初始化中冻结事件循环的段用 asyncio.to_thread 挪出主循环,或推迟到首屏之后。令 overview/scripts/setting 等从 17s 降至毫秒级。
  • Phase 2 — SRA 5 卡转前端:新建前端 composable 直连 starrailassistant.top/api/v1/activity/{game}.json,逐卡超时/缓存/退避;类型复用 types/home.tsSraActivityOverview
  • Phase 3 — 重返未来转前端:复用 Phase 2 管线,仅 URL/字段不同。
  • Phase 4 — 终末地决策点。建议先留后端(Phase 1 解冻后测实测再定);完整 TS 移植(7 文件管线 + i18n + 时区)成本高,仅当解冻后仍显慢才投入。
  • Phase 5 — 后端瘦身/get/overview 移除已迁前端的服务,只回 Stage + Proxy(或拆 /overview/local);删除后端无调用方的活动服务/缓存,避免双份逻辑漂移。

结构性风险

  • 第三方源改格式/挂掉:前端逐卡独立超时 + 失败态;保留后端缓存作兜底(Phase 1 后成本低)。
  • 跨端逻辑双份/漂移:Phase 5 删除后端旧逻辑,只留单一归属方。
  • 终末地复刻成本:先 A 后 B,以实测决定,不预先投入。
  • file:// + * CORS 边角:已实测 null 源可用,生产无凭证请求确认即可。
  • 引导期/路由门禁未同步改:Phase 0 独立前置。

优先级建议

Phase 0 → Phase 1 → 评估 → Phase 2 →(Phase 3/4 按实测)。Phase 0+1 即可将「全空十秒」降为亚秒级且带骨架,且是「全前端」方向的共同前提(方舟/代理依赖 Phase 1);Phase 2 为拟定方向的核心落地,以实测决定 Phase 4 的 A/B。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions