Repository navigation
fix(manage): 依赖健康检查不再随依赖路径数爆炸(修「打开管理页就未响应」) - #93
Open
std-external wants to merge 1 commit into
Open
std-external wants to merge 1 commit into
std-external wants to merge 1 commit into
Conversation
The dependency health check walked every dependency path. A Mod that several Mods depend on (a shared helper layer) is reachable through all of them, so the walk grew with the number of paths: opening the 管理 Mod page ran it for every Mod several times per render, which freezes the window for seconds or minutes on a large Mods folder. - Visit each Mod at most once per check (the visited set still stops cycles). - Only walk when the health filter actually asks for it; the default view does not need the result. Measured on a Mods folder of 300 Mods with a 20-Mod helper layer (each helper depending on the next two): 2.2-3.3s per render before, 0.1-12ms after; with three dependencies per helper the old code did not finish in 4 minutes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
打开「管理 Mod」页时整个窗口卡死(Windows 未响应)。有玩家在小 Mod 列表上没感觉,Mod 装得多、helper 之间互相依赖时一进管理页就假死。
原因
getDependencyHealth()(src/celemod-ui/src/stores/manage.ts:413)做依赖健康检查时用的是一个「当前路径」集合,递归返回后就把节点从集合里删掉。于是同一个 Mod 会被它经过的每一条依赖路径各走一遍,代价随路径数增长 —— helper 层共用得越多,路径数越爆炸。而它在这两个地方每次渲染都会被调用:
selectVisibleRootNames()对每一个 Mod 都调用一次,而且不管健康筛选是不是all都算;ManageTreeNode(src/celemod-ui/src/routes/Manage.tsx:840)每渲染一行都调用一次(只为了错误徽标)。所以打开管理页 = 一次渲染里跑几百次指数级的依赖遍历,主线程被 JS 占住 → 窗口假死。
本机实测(300 个 Mod + 20 个 helper,每个 helper 依赖后面两个):
selectVisibleRootNames管理页每次渲染要跑两遍
selectVisibleRootNames,所以默认视图以前就是 4.4–6.7 s 的白屏/假死,重一点的依赖图直接无限等下去。修复
getDependencyHealth():一次检查里每个 Mod 只访问一次(visited 集合同时继续用来挡循环依赖)。同一个 Mod 无论从哪条路径到达,它自己的依赖和状态都一样,所以状态结论不变,只是不再重复走路径(顺带不会再把同一条问题重复塞进徽标提示)。selectVisibleRootNames():健康筛选是all(默认)时不再计算依赖健康,先跑其它便宜的筛选条件。验证
src/celemod-ui/src/manageDependencies.test.ts,用 Proxy 统计节点访问次数):旧代码这两个测试 90 秒都跑不完,新代码 0.8 ms / 6.6 ms。node --import tsx --test src/manageDependencies.test.ts src/manageDisplayNames.test.ts20 个全过。npx tsc --noEmit通过;test:mod-updates/test:crash-trace/test:deep-link/test:catalog-download通过。另外发现(未改,供参考)
管理页调用的
apply_mod_profiles、resolve_duplicate_mod_files、switch_mod_profile_mods、update_blacklist_mod_file、get_current_profiles等都是同步 tauri 命令(在主线程执行),而blacklist.rs里它们又会调用get_installed_mods_sync()→ 整目录扫描 +get_mod_cached_new()(目录缓存不新鲜时最多阻塞 8 秒)。这条路径也可能是「未响应」的来源,但那需要具体环境才能定论,这次没动。来源:Celeste 玩家交流群反馈(一开管理页就未响应)。