perf(marketplace,localasr): 清理冗余定时器#674
Conversation
issue #470: - Marketplace 上传后双重 setTimeout(1.5s+5s) 去重为单次 5s——乐观更新已即时反映「我的 发布」,延时刷新仅做服务端状态校准,1.5s 那次纯冗余。 - LocalAsr scheduleScrollGuardRestore 三连 setTimeout(0/80/200ms) 仅删等价的 0ms 那枪 (已被紧随的 rAF 覆盖),保留 80/200ms 兜住 rAF 之后的异步重排,避免滚动跳变回归。
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
|
Claude finished @appergb's task in 2m 13s —— View job PR 审查:清理冗余定时器 (#470 #8/#9)
Marketplace.tsx — 去重 1.5s+5s → 单次 5s乐观更新覆盖:✅ 正确 上传成功(收到 200)后, 边界情况 // Marketplace.tsx:340, 345
const localPack = localPacks.find(p => p.id === packId);
// ...
if (localPack && currentLogin) { // 两个条件都需满足才走乐观更新
setMyPacks(...)
}若 5s 延时合理性:✅ LocalAsr.tsx — 删除
|
| 触发点 | 原始 | 修改后 |
|---|---|---|
| ~0ms | setTimeout(0) ✓ |
✗ |
| ~16ms | rAF → restoreScrollGuard ✓ |
rAF → restoreScrollGuard ✓ |
| ~32ms | nested rAF ✓ |
nested rAF ✓ |
| ~80ms | setTimeout(80) ✓ |
setTimeout(80) ✓ |
| ~200ms | setTimeout(200) ✓ |
setTimeout(200) ✓ |
| 每次 render | useLayoutEffect(() => restoreScrollGuard()) ✓ |
同左 ✓ |
setTimeout(0) 在浏览器实际延时约 0–4ms,早于 rAF(~16ms)触发。删除后存在约 0–16ms 的覆盖空白:若在此窗口内有非 React 驱动的同步 DOM 重排(如第三方库、WebView 原生行为),restoreScrollGuard 会晚 ~16ms 才被调用,理论上可能闪现一帧滚动跳变。
但考虑到:
useLayoutEffect(无依赖数组,每次渲染后同步运行)已覆盖所有 React-driven reflow;- 触发场景(Sherpa 模型加载/切换引起的异步重排)属于 IO 异步,不会在同步帧内立即触发滚动;
- 原有 rAF + nested rAF 在实际使用中未见问题。
结论:0ms 那枪删除等价性 ✅(实践中覆盖,理论缺口可忽略)
80/200ms 保留是否足以防滚动跳变:✅
80ms 覆盖快速异步资源(如 Sherpa 引擎返回的文本触发的快速重排),200ms 覆盖更慢的异步操作(图片晚加载、WebView 字体渲染)。两个守卫足够兜住 rAF 之后的异步 layout shift。
一处值得关注的细节(非本 PR 引入,既有问题):
// LocalAsr.tsx:203-211
const scheduleScrollGuardRestore = () => {
window.setTimeout(restoreScrollGuard, 80) // ← 返回的 id 未存储
window.setTimeout(restoreScrollGuard, 200) // ← 同上
window.requestAnimationFrame(() => { ... })
}80/200ms 的 timer id 没有被追踪——deactivate 只清理 scrollGuardTimer(10s 那个),不清理这两个。调用 deactivate(用户滚动/点击/10s 超时)后,scrollGuard.current 会被置 null,restoreScrollGuard 开头的 if (!guard) return 会让它们变成 no-op,不会导致错误,但有轻微的泄漏感知。这是既有行为,与本 PR 无关,可在后续清理。
总结
| 改动 | 正确性 | 建议 |
|---|---|---|
| Marketplace: 去掉 1.5s timer | ✅ 可合入 | 可在 PR 描述补充"localPack 为 null 时退化为 5s"以备查 |
| LocalAsr: 删 setTimeout(0) | ✅ 可合入 | 0–16ms 理论缺口无实际影响 |
| LocalAsr: 保留 80/200ms | ✅ 保守正确 | — |
整体评价:改动保守、论证充分,可以合入。
User description
源自 #470 Cloud 性能审查 #8/#9。
setTimeout(1.5s+5s)去重为单次 5s——乐观更新已即时反映「我的发布」,延时刷新仅做服务端状态校准,1.5s 那次纯冗余。scheduleScrollGuardRestore三连setTimeout(0/80/200ms)仅删等价的 0ms 那枪(已被紧随 rAF 覆盖),保守保留 80/200ms 兜住 rAF 之后的异步重排,避免滚动跳变回归。验证:
npm run build通过。PR Type
Enhancement
Description
移除 MarketPlace 上传后的冗余 1.5s 定时器,仅保留 5s 兜底刷新
移除 LocalAsr 滚动保护中的 setTimeout(…,0),保留 80ms/200ms 兜住异步重排
Diagram Walkthrough
File Walkthrough
LocalAsr.tsx
移除冗余的 setTimeout(…,0)openless-all/app/src/pages/LocalAsr.tsx
setTimeout(restoreScrollGuard, 0)调用(被紧随的 rAF 覆盖)Marketplace.tsx
去除上传后双重 setTimeout,仅保留 5sopenless-all/app/src/pages/Marketplace.tsx