Skip to content

perf(onboarding,settings): 权限/热键状态纯事件驱动,去掉高频轮询 - #673

Merged
appergb merged 2 commits into
betafrom
fix/470-frontend-permission-eventdriven
Jun 16, 2026
Merged

perf(onboarding,settings): 权限/热键状态纯事件驱动,去掉高频轮询#673
appergb merged 2 commits into
betafrom
fix/470-frontend-permission-eventdriven

Conversation

@appergb

@appergbappergb commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

User description

源自 #470 Cloud 性能审查 #3/#4/#5。引导页桌面(1s)/Android(3s)、设置页热键(1s) 的高频权限/热键 setInterval 轮询全部改为 focus/visibilitychange 事件驱动,连低频兜底也去掉(纯事件驱动)。

覆盖论证:麦克风前台原生弹窗授予由申请结果回调 + 800ms 兜底覆盖;辅助功能授予必经系统设置 App、切回必触发 focus/visibilitychange。并给 onGrantAccessibility 补对称的 void refresh() + 800ms 兜底。refreshPermissions(10s)/refreshNetwork(30s) 保留不动。

验证npm run build 通过 + 对抗式复审(已修复其指出的 floating-promise)。


PR Type

Enhancement


Description

  • 移除高频轮询,改用 focus/visibilitychange 事件驱动

  • 添加 visibilitychange 事件监听,确保从系统设置返回后立即刷新

  • 对称处理麦克风和辅助功能授权后的刷新逻辑

  • 统一代码风格(void refresh())消除 floating promise


File Walkthrough

Relevant files
Performance improvement
Onboarding.tsx
事件驱动替代轮询 + 授权刷新对称处理

openless-all/app/src/components/Onboarding.tsx

  • AndroidMicrophoneStep: 移除 3 秒轮询,改为 focus + visibilitychange 事件
  • DesktopOnboarding: 移除 1 秒轮询,添加同类事件监听
  • onGrantAccessibility: 添加同步刷新 + 800ms 超时兜底
  • 所有 refresh() 调用加 void(修复 floating promise)
+14/-6
PermissionsSection.tsx
Settings 页热键状态改为纯事件驱动

openless-all/app/src/pages/settings/PermissionsSection.tsx

  • 移除热键 1 秒轮询(retain 10s/30s 低频轮询)
  • 添加 focus + visibilitychange 事件驱动刷新所有状态
  • 统一焦点事件处理逻辑
+6/-5

issue #470:引导页桌面(1s)/Android(3s)、设置页热键(1s) 的 setInterval 高频权限/热键轮询
全部改为 window focus / visibilitychange 事件驱动,连低频兜底也去掉(纯事件驱动)。
覆盖论证:麦克风前台原生弹窗授予由申请结果回调 + 800ms 兜底覆盖;辅助功能授予必经系统
设置 App、切回 OpenLess 必触发 focus/visibilitychange。并给 onGrantAccessibility 补对称的
void refresh() + 800ms 兜底(与 onRequestMicrophone 对齐)。PermissionsSection 的
refreshPermissions(10s)/refreshNetwork(30s) 保留不动。
@appergb

Copy link
Copy Markdown
CollaboratorAuthor

@claude 请审查本 PR(#470#3/#4/#5:权限/热键状态纯事件驱动)。重点核查删掉所有高频/低频定时器后授予路径是否仍全覆盖(麦克风申请结果回调、辅助功能 focus/visibilitychange、onGrantAccessibility 补的 800ms 兜底),listener 清理是否到位无泄漏,10s/30s 两个定时器是否保留。

@github-actions

github-actionsBot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit d221ee2)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis ❌

4 - Not compliant

Non-compliant requirements:

  • 未添加翻译目标语言设置项
  • 未实现 Shift 组合键触发
  • 未添加 translate prompt 模板
  • 未更新胶囊 UI 翻译模式标签

5 - Not compliant

Non-compliant requirements:

  • 未添加 F5 或双击快捷键支持
  • 未优化组件描述 prompt 注入

470 - Not compliant

Non-compliant requirements:

  • PR 未修改 Windows 胶囊渲染相关代码,未直接修复胶囊不显示问题
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@claude

claudeBot commented Jun 15, 2026

Copy link
Copy Markdown

Claude finished @appergb's task in 2m 24s —— View job


PR #673 代码审查

  • 获取上下文,读取变更文件
  • 核查麦克风申请结果回调覆盖
  • 核查辅助功能 focus/visibilitychange 覆盖 + onGrantAccessibility 800ms 兜底
  • 核查 listener 清理(无泄漏)
  • 核查 10s/30s 定时器是否保留
  • 汇总审查结论

总体结论

逻辑设计正确,授予路径全覆盖,cleanup 无泄漏,两个长周期定时器保留完好。发现 1 个需修复的 floating-promise(DesktopOnboarding 的 refresh() 调用未加 void)和 2 个较小建议。


各项核查

1. 麦克风申请结果回调覆盖 ✅

AndroidMicrophoneStepOnboarding.tsx:234-246):

  • request() 内部:setStatus(await requestAndroidMicrophoneAccess()) 直接从回调结果更新状态,后接 await refresh() 做双重确认。授予结果即时体现,无需等待 focus。
  • focus/visibilitychange 兜底用户从系统设置返回的场景,逻辑完整。

DesktopOnboarding onRequestMicrophoneOnboarding.tsx:331-348):

  • requestMicrophonePermission() 返回值直接 setMicrophone(status),状态即时更新。
  • 追加 800ms setTimeout(refresh, 800) 作为二次确认。✅

2. 辅助功能 focus/visibilitychange + onGrantAccessibility 800ms 兜底 ✅

onGrantAccessibilityOnboarding.tsx:317-329):

voidrefresh();// 立即刷新if(refreshTimeoutRef.current)clearTimeout(refreshTimeoutRef.current);refreshTimeoutRef.current=window.setTimeout(refresh,800);// 800ms 兜底
  • requestAccessibilityPermission() + openSystemSettings('accessibility') 之后立即 void refresh(),再接 800ms 定时兜底。
  • 用户必须离开 app 进入系统设置 → 切回时必触发 focus/visibilitychange,两条路径均覆盖。✅

3. Listener 清理(无泄漏)✅

AndroidMicrophoneStepOnboarding.tsx:228-231):

return()=>{window.removeEventListener('focus',onFocus);document.removeEventListener('visibilitychange',onVisibility);};

DesktopOnboardingOnboarding.tsx:310-314):

return()=>{window.removeEventListener('focus',onFocus);document.removeEventListener('visibilitychange',onVisibility);if(refreshTimeoutRef.current)clearTimeout(refreshTimeoutRef.current);};
  • refreshTimeoutRef 在 cleanup 中也已清除,防止卸载后 refresh() 被调用。✅

PermissionsSectionPermissionsSection.tsx:101-106):

return()=>{window.clearInterval(permissionId);window.clearInterval(networkId);window.removeEventListener('focus',onFocus);document.removeEventListener('visibilitychange',onVisibility);};

全部清理,无泄漏。✅


4. 10s/30s 定时器保留 ✅

PermissionsSection.tsx:85-86

constpermissionId=window.setInterval(refreshPermissions,10000);// ✅ 保留constnetworkId=window.setInterval(refreshNetwork,30000);// ✅ 保留

问题

🔴 Floating Promise(需修复)— DesktopOnboarding

PR 描述声称已修复 floating-promise,但 DesktopOnboardingrefresh() 的三处调用未加 void。对比 AndroidMicrophoneStepvoid refresh() 写法不一致。

Onboarding.tsx 第 304、306、307 行:

// 当前(浮动 Promise)useEffect(()=>{refresh();// 行 304constonFocus=()=>refresh();// 行 306constonVisibility=()=>{if(...)refresh();};// 行 307
...
},[requiresAccessibility]);// 建议useEffect(()=>{voidrefresh();constonFocus=()=>{voidrefresh();};constonVisibility=()=>{if(document.visibilityState==='visible')voidrefresh();};
...
},[requiresAccessibility]);

Fix this →


🟡 PermissionsSection refreshAll() 中的浮动 Promise(非本 PR 引入,建议跟进)

PermissionsSection.tsx:87-96refreshAll() 内部调用 refreshPermissions()refreshHotkey() 等均为 async 函数,无 voidawait。这个模式在文件其它位置(如 refreshPermissions() 直接调用行 75)已存在,非本 PR 引入,可在后续统一修复。


🟡 refreshAll() 在每次 focus 时也触发 refreshNetwork()

PermissionsSection.tsx:94refreshNetwork() 出现在 refreshAll() 中,因此每次用户切回窗口都会触发网络检查(除了 30s 周期外)。对网络延迟较高的环境影响可忽略,但若 focus 触发非常频繁(如快速 cmd+tab)会产生多次并发网络请求。若要更保守,可考虑将网络检查仅保留在 30s 定时器中,不放入 refreshAll()。优先级低,供参考。


@HKLHaoBin

Copy link
Copy Markdown
Contributor

@claude 审查 #673 指出:DesktopOnboarding 的 useEffect 里 refresh()/onFocus/onVisibility
三处 refresh() 是 floating promise(与上方 Android 段的 void refresh() 不一致,IPC 失败会
静默)。统一加 void 明确 fire-and-forget。issue #470
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit d221ee2

@appergb
appergb merged commit ee42d1a into betaJun 16, 2026
5 checks passed
@appergb
appergb deleted the fix/470-frontend-permission-eventdriven branch June 16, 2026 03:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@appergb@HKLHaoBin