Skip to content

fix(reminder): ExpoLocationMonitor.chainSync() 在 syncRegions() 意外抛错时有崩溃风险 - #348

Merged
LUPENGHAN merged 1 commit into
1024XEngineer:mainfrom
LUPENGHAN:fix/expo-location-syncchain-unhandled-rejection
Aug 21, 2026
Merged

fix(reminder): ExpoLocationMonitor.chainSync() 在 syncRegions() 意外抛错时有崩溃风险#348
LUPENGHAN merged 1 commit into
1024XEngineer:mainfrom
LUPENGHAN:fix/expo-location-syncchain-unhandled-rejection

Conversation

@LUPENGHAN

Copy link
Copy Markdown
Contributor

变更说明

ExpoLocationMonitor.chainSync() 之前用 .then(onFulfilled, onRejected) 排队执行 syncRegions()syncRegions() 内部两处 getForegroundPermissionsAsync()/getBackgroundPermissionsAsync() 调用没有包 try/catch,一旦原生定位模块真的抛出异常(不是返回 denied),这次失败要等到下一次 chainSync() 调用才会被接住。handleAppState 里触发的那条重同步路径是发射后不管的(void this.chainSync()),如果失败恰好发生在那里、短时间内又没有下一次调用兜底,这个被拒绝的 promise 就会一直没人处理,被 JS 运行时判定成 unhandled rejection,直接把 App 进程崩溃退出。

改成 .then(onFulfilled).catch(() => {})——跟同项目 AssistantContinuousConversationService.chainPlayback() 已经在用的写法一致,.catch() 在同一条语句里同步接上,不会再有"没人接"的窗口期。

Closes #347

测试计划

  • npx jest --runInBand(前端全量,614/614 绿)
  • npx tsc --noEmit
  • npx eslint(改动到的文件)
  • 补了回归测试:mock 一次定位权限查询真实 reject,通过 handleAppState 触发同步,验证进程不崩溃、后续同步能正常恢复;已验证过旧代码上这条测试会失败(复现了同一个 unhandled rejection)

🤖 Generated with Claude Code

…ns()

syncRegions() has two unguarded awaits (getForegroundPermissionsAsync/
getBackgroundPermissionsAsync) that can reject for real on a native module
hiccup, not just resolve to a denied status. chainSync() chained with
.then(onFulfilled, onRejected), so a rejection sits unhandled until some
later chainSync() call chains onto it. handleAppState's resync is
fire-and-forget (void this.chainSync()) with no such follow-up guaranteed --
if the rejection lands there, Node/Hermes treats it as an unhandled
rejection and crashes the process outright. Reproduced with a mocked
permission call that rejects.

Switch to .then(onFulfilled).catch(() => {}), the same idiom already used by
AssistantContinuousConversationService.chainPlayback(): the .catch() is
attached in the same statement, so the rejection is neutralized immediately
instead of waiting on a future call that may never come.

Fixes 1024XEngineer#347.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@LUPENGHAN
LUPENGHAN marked this pull request as ready for review August 21, 2026 07:50
@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审阅了固定提交范围 81438d1511307b560a67bab2cc96f7184fb5df71...c51024957481d7b60cfecad5bbcaa597a6101e6b 中的 ExpoLocationMonitor.chainSync() 及其回归测试。将 rejection handler 从 .then(onFulfilled, onRejected) 改为同一表达式中的 .then(...).catch(...),确实会立即覆盖 fire-and-forget 的 handleAppState 路径,同时保留后续同步继续排队的行为;新增测试也覆盖了失败后的恢复路径。未发现满足报告阈值的正确性、可靠性或兼容性问题。

验证:git diff --check 通过。尝试运行聚焦 Jest 测试,但当前工作区未安装依赖,jest-expo preset 缺失,因此未能执行测试。

@LUPENGHAN
LUPENGHAN merged commit dd0a5fc into 1024XEngineer:main Aug 21, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(reminder): ExpoLocationMonitor.chainSync() 在 syncRegions() 意外抛错时有崩溃风险

2 participants