Skip to content

🐛 更新页不再倒计时自动关闭,记录失效改为自动重查续做 - #1720

Merged
CodFrm merged 4 commits into
mainfrom
fix/batchupdate-remove-autoclose
Sep 8, 2026
Merged

CodFrm merged 4 commits into
mainfrom
fix/batchupdate-remove-autoclose

Conversation

@CodFrm

@CodFrm CodFrm commented Sep 3, 2026 •

Copy link
Copy Markdown
Member

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

背景

定时检查发现有更新后,用户导航到命中站点的域名时,SW 会抢焦点弹出批量更新页,并在 URL 上带 autoclose=30;页面倒计时归零直接 window.close()。#1715 报的就是"认真读页面上每个字,没看完页面就没了",而 #1087 报过同一件事——当时的处理是把 8 秒延长到 30 秒,service_worker/index.ts 里也留了"关于 autoclose,日后再检讨 UI/UX 设计"的注释。

倒计时是在补偿"我们擅自弹出了一个你没要求的标签页",方向反了:更新页同时是打扰源和决策界面,给决策界面装秒表只会把打扰变成焦虑。而且页面上唯一不刹车的交互恰好是"点脚本名看差异"——该链路要先联网 fetch 脚本源码才开出安装页,这几秒里倒计时照走,列表页可能在用户读差异时于后台自行关闭。

本次改动

去掉自动关闭机制(不是调参、不是加开关):URL 参数两处产地、hooks.ts 的倒计时状态与两个 effect、AutoCloseChip 组件与两个 props、移动端的分支渲染、10 个语言包的 3 个 key,以及 e2e 冒烟用例里残留的 &autoclose=30 一并移除。更新页从此只在用户点关闭时才关。

记录失效改为自动重查续做:删掉倒计时后页面会长时间开着,这暴露了原本被 30 秒关窗掩盖的问题——批量更新记录(ScriptUpdateCheck.cacheFull)只存在 Service Worker 内存里,页面通过 chrome.runtime.sendMessage 广播订阅、不持有长连接,因此不给 SW 保活;SW 闲置回收后再点更新只会拿到 record_expired,用户面对的是"按钮点了没用,请重新检查"。现在首次失效自动重新检查一次并接着做完剩余条目,重查后已经是最新的条目静默出队(不计为失败、不弹汇总),二次失效才落回原来的 RecordExpiredNotice。

实现考虑

  • runUpdates 从固定 for 改成可变队列 + 下标:失效时下标停在原地、队列换成重查后的剩余项,rechecked 保证每次调用只自动重查一次,避免死循环。批量进度的 total 随队列长度重算;整批都已是最新时不留汇总条也不弹 toast。
  • 重查走 checkScriptUpdate({ checkType: "user" }),不传 noUpdateCheck,因此不会命中 canSkipScriptUpdateCheck 的节流;SW 侧该调用会 await 完整检查后才返回,页面可以直接串行等待。重查期间 SW 广播 CHECKING_UPDATE,页面顶部进度条即为反馈,未新增 UI 或文案。
  • 出队判定用重查后记录里的 checkUpdate 字段,而不是 categorize().updates——后者会排除已忽略项,会让"全部恢复并更新"路径把待办条目误判成已完成。
  • 自动重查不设置 userCheckPendingRef,因此不会像手动"检查更新"那样弹"发现 N 个更新"的 toast。

已知限制

  • 更新页仍然是 chrome.tabs.create 默认 active: true 抢焦点弹出的,只是不再自己关。是否改成后台标签打开属于弹出策略,本 PR 不动。
  • 未在真实浏览器里驱动构建产物。删倒计时由单测直接证伪;record_expired 自动重查是在 hook 边界用打桩的 SW 响应验证的,真实 SW 被回收那一刻的行为没有实机观察。
  • 顺带发现但未处理(不在本 PR 范围):GM 权限确认页 src/pages/confirm/App.tsx 的 30 秒倒计时会自动按"忽略"并关窗,且不因 document.hidden 暂停、没有任何交互刹车。它有正当理由(脚本调用阻塞中,必须有结论),但那两条缺陷值得单独修。

建议审查重点

  • 批量更新中途失效后重新检查、队列重排与进度条 total 的一致性(runUpdates 的 while 循环)。
  • 单条更新在重查后条目消失时,行状态被清掉且不报错,是否符合预期。
  • 二次失效仍然落到 RecordExpiredNotice,没有把用户困在无限重试里。

关联

close #1715 —— 同一诉求此前在 #1087 出现过,当时只延长了倒计时。

验证

范围绑定:base 61164f69 → head 80c7dd26,git diff 61164f69...80c7dd26 --stat = 18 文件 +159/−256,全部落在 batchupdate 页面、其两处 URL 产地、10 个语言包与一条 e2e 冒烟用例内,无其它清理。

  • pnpm run lint → exit 0(prettier + tsc --noEmit + check:i18n + check:issue-templates + eslint 全过)
  • npx vitest run src/pages/batchupdate src/pages/install/useInstallData.test.ts src/app/service/service_worker/script.test.ts src/locales/i18n-usage.test.ts → 6 文件 195/195 通过
  • TDD 红→绿:新增的 URL 仍带 autoclose 参数时也不会自行关闭 在实现前失败于 expected "bound close" to not be called at all, but actually been called 1 times;4 个改写的"更新数据过期"用例实现前全部超时失败。
  • pnpm test 全量在本机因并发超时(testTimeout 850ms)大面积假失败,与本改动无关:同一份 main 代码两次跑分别是 3 failed 和 443 failed / 129 文件,本分支两次是 38 failed 和 170 failed,失败集中在 scripts/check-i18n.test.mjs、src/pkg/utils/match.test.ts、popconfirm.test.tsx 等与 diff 无关的文件。所有涉及文件单独跑均通过(见上一条)。

追加调整:全局唯一批量更新页

为避免用户长时间未处理、后台重复触发时打开多个批量更新页,openBatchUpdatePage 现在会先查询已有的 batchupdate.html 标签页:

  • 已存在时激活该标签并聚焦所在窗口,不再创建新页;
  • 不存在时才按原流程创建页面;
  • 自动弹出、设置页及其他调用方都经过同一 Service Worker 入口;
  • 页面关闭后,下次触发仍可重新创建;
  • 不改变后台检查、缓存和过期重查策略。

验证:pnpm test -- --run src/app/service/service_worker/script.test.ts(当前项目测试配置实际执行全量套件,365 个测试文件、4596 个测试通过);提交前类型检查、Prettier、issue template 检查均通过。

自动弹出的批量更新页带 autoclose=30,30 秒后 window.close(),用户还没读完
更新说明页面就自己没了(#1715)。倒计时是在补偿「抢焦点弹出一个没人要求的标签
页」,方向反了:整套机制连同 URL 参数、药丸组件与三个 i18n key 一并移除。

页面因此会长时间开着,这暴露了原本被 30 秒关窗掩盖的问题:批量更新记录只存在
Service Worker 内存里,SW 被回收后点更新只会拿到 record_expired。现在首次失效
自动重新检查一次并接着做完剩余条目,重查后已是最新的条目静默出队、不计为失败,
二次失效才提示用户重新检查。

close #1715
@cyfung1031

cyfung1031 commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator

「 更新页不再倒计时自动关闭」暂时没意见。之后有需要再处理
或者你可以把自动关闭改到15分钟
否则有机会会重复弹 (例如长时间挂机)

Agent好像也发现这个设计是预设会关掉的
强制不关的话可能会有问题

或者你只改参数把 auto_close 设为 -1 会简单一点

@cyfung1031

Copy link
Copy Markdown
Collaborator

#1721 (comment)

@Mishasama

Copy link
Copy Markdown
  1. 对于批量更新记录(ScriptUpdateCheck.cacheFull)只存在于 Service Worker 内存里的问题,我想是不是可以把这些东西放到Cache storage或者Extension storage之类的存储空间里?这样,在 SW 失效需要再次加载的时候,就可以直接回调,不需要重新下载或者触发重复动作等。
  2. 另外,对于是否要抢前台,我的建议是不要抢。在后台弹出页面后,通过浏览器推送一个持久化的系统通知,点击通知即可跳转到更新页面。这样无论是 PC 还是移动端都非常友好。

@cyfung1031

cyfung1031 commented Sep 5, 2026 •

Copy link
Copy Markdown
Collaborator

对于批量更新记录(ScriptUpdateCheck.cacheFull)只存在于 Service Worker 内存里的问题,我想是不是可以把这些东西放到Cache storage或者Extension storage之类的存储空间里?这样,在 SW 失效需要再次加载的时候,就可以直接回调,不需要重新下载或者触发重复动作等。

最初只是一个小功能。不想搞太多。所以只存在于 Service Worker 内存里。
(注意:如何判断 cache 有效没过时等处理。)
要改的话也可以但要详细测试(包括实机测试)
让 CodFrm 判断和处理吧

另外,对于是否要抢前台,我的建议是不要抢。在后台弹出页面后,通过浏览器推送一个持久化的系统通知,点击通知即可跳转到更新页面。这样无论是 PC 还是移动端都非常友好。

我的机器基本上没有系统通知功能。(个人问题不使用)
还是那句最初只是一个小功能。不想搞太多。
要改的话也可以但要详细测试(包括实机测试)
让 CodFrm 判断和处理吧

@CodFrm

CodFrm commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

「 更新页不再倒计时自动关闭」暂时没意见。之后有需要再处理 或者你可以把自动关闭改到15分钟 否则有机会会重复弹 (例如长时间挂机)

Agent好像也发现这个设计是预设会关掉的 强制不关的话可能会有问题

或者你只改参数把 auto_close 设为 -1 会简单一点

或者考虑全局只会自动的打开一个batchupdate窗口,之前的脚本更新加自动关闭主要是考虑到用户可能长时间不用/在后台,会打开非常多的更新窗口,导致混乱

@CodFrm

CodFrm commented Sep 5, 2026 •

Copy link
Copy Markdown
Member Author
  1. 对于批量更新记录(ScriptUpdateCheck.cacheFull)只存在于 Service Worker 内存里的问题,我想是不是可以把这些东西放到Cache storage或者Extension storage之类的存储空间里?这样,在 SW 失效需要再次加载的时候,就可以直接回调,不需要重新下载或者触发重复动作等。

我觉得还好,这个检查更新是每次都要去检查更新的,如果是一个过期的数据就有点失去意义了

  1. 另外,对于是否要抢前台,我的建议是不要抢。在后台弹出页面后,通过浏览器推送一个持久化的系统通知,点击通知即可跳转到更新页面。这样无论是 PC 还是移动端都非常友好。

这个点再考虑吧,系统通知很容易被忽略(而且有的用户没有给权限),如果不想更新就设置不检查更新/延长时间好了

冲突全部落在 #1719 同样重写过的批量更新页上,按「保留 main 的新能力 + 删掉自动关闭」解:

- hooks.ts `runUpdates`:main 的批量互斥(batchRunningRef + try/finally)与中断汇总
  (interrupted)保留,循环换成本分支的可变队列 + 下标,失效时先自动重查续做;
  重查后仍失效才落到 recordExpired,并按 main 的口径留下 interrupted 汇总而不是抹掉进度。
- runIgnores / runCheckNow / onOpen / onRetryLoad 取 main,仅摘掉其中的 cancelAutoClose。
- components.tsx、mobile.tsx、components.test.tsx:保留 onRetryLoad,去掉 onCancelAutoClose
  与 AutoCloseChip。
- hooks.test.ts:删掉随功能一并移除的「点开更新详情停掉倒计时」用例;recheckYields 改回
  main 收敛后的 TCheckScriptUpdateResult;「中断保留已完成条数」补上第二次 record_expired,
  因为第一次现在会触发自动重查。
main HEAD(999d2cd) 的 Lint 就因这 5 个文件 fail,与本 PR 的改动无关,
纯机械 prettier --write,无语义变化。
@CodFrm
CodFrm merged commit 0f70a99 into main Sep 8, 2026
10 checks passed
@CodFrm
CodFrm deleted the fix/batchupdate-remove-autoclose branch September 8, 2026 01:54
@Mishasama

Copy link
Copy Markdown
  1. 对于批量更新记录(ScriptUpdateCheck.cacheFull)只存在于 Service Worker 内存里的问题,我想是不是可以把这些东西放到Cache storage或者Extension storage之类的存储空间里?这样,在 SW 失效需要再次加载的时候,就可以直接回调,不需要重新下载或者触发重复动作等。

我觉得还好,这个检查更新是每次都要去检查更新的,如果是一个过期的数据就有点失去意义了

正常情况下可能是这样,但是要是 SW 因任何原因而discard/close了之类的呢?
现代浏览器的“优化”可是可以很激进的,用户的使用环境也可能不太稳定。一套万全的方案可以体现出作者的设计功底,用户体验也能在任何时候都保持一致的高水平。(既然都想出来了,就不想输给TM啊!😂)

  1. 另外,对于是否要抢前台,我的建议是不要抢。在后台弹出页面后,通过浏览器推送一个持久化的系统通知,点击通知即可跳转到更新页面。这样无论是 PC 还是移动端都非常友好。

这个点再考虑吧,系统通知很容易被忽略(而且有的用户没有给权限),如果不想更新就设置不检查更新/延长时间好了

正因为容易被忽略,所以才要设计成持久化的通知。用户给不给权限是用户的使用偏好(就跟功能开关一样),不代表这部分功能的体验就不需要做好,这不是一回事。
比如,我就是长期开机离开岗位,回岗位后第一时间看到的就是正在显示的通知,也优先处理看到通知的事项。我是比较依赖通知对我的“干扰”来定义任务的优先级的……(ADHD)😅

@cyfung1031

Copy link
Copy Markdown
Collaborator

正常情况下可能是这样,但是要是 SW 因任何原因而discard/close了之类的呢?
现代浏览器的“优化”可是可以很激进的,用户的使用环境也可能不太稳定。一套万全的方案可以体现出作者的设计功底,用户体验也能在任何时候都保持一致的高水平。(既然都想出来了,就不想输给TM啊!😂)

现在的是最好最先进的
被优化导致资料不见的话,最保险就是重新下载而不信任 cache。你怎知道 cache 被「优化」的程度。
所以是故意不做长期cache

有很多考虑啦。功能不是愈多愈好。

其他UI/UX相关等 CodFrm 回答

@CodFrm

CodFrm commented Sep 23, 2026 •

Copy link
Copy Markdown
Member Author
  1. 另外,对于是否要抢前台,我的建议是不要抢。在后台弹出页面后,通过浏览器推送一个持久化的系统通知,点击通知即可跳转到更新页面。这样无论是 PC 还是移动端都非常友好。

这个点再考虑吧,系统通知很容易被忽略(而且有的用户没有给权限),如果不想更新就设置不检查更新/延长时间好了

正因为容易被忽略,所以才要设计成持久化的通知。用户给不给权限是用户的使用偏好(就跟功能开关一样),不代表这部分功能的体验就不需要做好,这不是一回事。 比如,我就是长期开机离开岗位,回岗位后第一时间看到的就是正在显示的通知,也优先处理看到通知的事项。我是比较依赖通知对我的“干扰”来定义任务的优先级的……(ADHD)😅

“用户给不给权限是用户的使用偏好”,如果改成系统通知的话,很多用户可能无意间就没有给浏览器通知权限,而且系统通知的设置很恶心,还可能是浏览器没有给扩展权限,扩展还无法检查+控制,这样就导致一些用户无法用到这个功能

不过我倒是有想法做成在用户访问页面的时候,将更新日志、脚本更新这些内容做成一个页面内的弹窗/浮窗,这样体验是不是更好一点

@Mishasama

Copy link
Copy Markdown

在用户访问页面的时候,将更新日志、脚本更新这些内容做成一个页面内的弹窗/浮窗,这样体验是不是更好一点

但是这样可能会与一些自动化脚本或视觉agent的任务发生冲突或干扰。

我觉得参考 TM 当前的做法已经足够了。实在不行,可以在扩展首次安装初始化的时候安排一个页面,指引用户给权限并设置相应的功能。

毕竟目前我们的主要用户都是从其他脚本管理器迁移过来的,尽可能维持一致的基础体验,减少学习成本,我认为这是最好的做法。(对标也要给别人容易比出优势的方式,在原有的基础上改进就是最直观的优势了)

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.

[BUG] 脚本更新确认倒计时设计不人性化

3 participants