-
Notifications
You must be signed in to change notification settings - Fork 309
[v1.3] 異步 getValue/getValues/listValues 相关修改 #950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/v1.3
Are you sure you want to change the base?
[v1.3] 異步 getValue/getValues/listValues 相关修改 #950
Conversation
|
怎么都到这个分支去了 develop/raw-message |
因为两边的 commit 互相影响 |
b6d77de to
31a4165
Compare
31a4165 to
dc9f387
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
这个 PR 实现了异步 getValue/getValues/listValues 相关的重要改进,主要解决了在多标签页并发场景下值读取的一致性问题。通过引入 waitForFreshValueState 机制和批处理架构,确保在读取值之前能够获得最新的状态。
主要变更:
- 新增
waitForFreshValueState方法,确保在读取前获取最新的 value 状态 - 重构
setValues方法为批处理架构,使用任务队列和setValuesByStorageName进行批量处理 - 修改
GM.getValue/GM.listValues/GM.getValues以在读取前等待最新状态
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/app/service/service_worker/value.ts | 核心变更:新增 waitForFreshValueState 和 setValuesByStorageName,重构 value 更新逻辑为批处理模式,引入 ValueUpdateTaskInfo 任务队列 |
| src/app/service/service_worker/value.test.ts | 更新测试以反映新的批处理行为,调整期望值以匹配新的数据结构,添加 flush() 调用处理异步逻辑 |
| src/app/service/service_worker/runtime.ts | 更新 valueUpdate 订阅以使用新的 TScriptValueUpdate 类型,添加脚本状态重新验证逻辑 |
| src/app/service/service_worker/permission_verify.ts | 更新泛型约束从 T 到 T extends Array<any> 以匹配 API 参数类型 |
| src/app/service/service_worker/gm_api/gm_api.ts | 新增 internalApiWaitForFreshValueState API 方法,修正权限链接配置 |
| src/app/service/sandbox/runtime.ts | 更新 valueUpdate 方法以处理新的 ValueUpdateSendData 数据结构 |
| src/app/service/queue.ts | 修改 TScriptValueUpdate 类型定义,从包含 Script 对象改为包含 uuid、status 和 isEarlyStart 字段 |
| src/app/service/content/types.ts | 在 ValueUpdateDataEncoded 中添加 updatetime 字段,新增 ValueUpdateSendData 类型 |
| src/app/service/content/script_executor.ts | 更新 valueUpdate 方法签名以适配新的数据结构 |
| src/app/service/content/inject.ts | 更新类型引用从 ValueUpdateDataEncoded 到 ValueUpdateSendData |
| src/app/service/content/gm_api/gm_api.ts | 实现 waitForFreshValueState 静态方法,更新 GM.getValue/GM.listValues/GM.getValues 以调用该方法,重构 valueUpdate 处理多个更新事件,引入 extValueStoreCopy 和 readFreshes 机制 |
| src/app/service/content/gm_api/gm_api.test.ts | 添加 valueDaoUpdatetimeFix 辅助函数,更新测试以处理新的 waitForFreshValueState 行为,修正正则表达式以匹配计数器格式 |
| src/app/service/content/exec_script.ts | 更新 valueUpdate 方法签名以传递 storageName、uuid 和数据列表 |
| const hold = deferred(); | ||
| // 避免立即 emit | ||
| stackAsyncTask("valueUpdateEventListenerEmit", () => hold.promise); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么不直接包裹,而且整个流程都是同步的,用stackAsyncTask的意义是什么
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果是想 完全处理完毕后再 emitToListener,我觉得不如直接把这个逻辑放在最后
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emitToListener 跟 valueChangePromiseMap 使用同一条 task 队列
valueUpdate 开始时,放了 stackAsyncTask("valueUpdateEventListenerEmit", () => hold.promise);
这让 emitToListener 先不开始处理
valueUpdate 完结后, hold.resolve(); 执行, emitToListener里的才开始处理
< 注意如果有其他 valueUpdate 的 valueChangeListener 未跑好,這輪的 valueChangeListener 也不會立即開始 >
用其他方法也可以
例如做一个 tasklist.
emitToListener 时把 this, key, oldValue, value, remote, sender.tabId 储存成一个 entry 放在 tasklist
最后 forloop 执行
这样写比较长,但效果一样
(這個只能考慮同一輪的valueChangeListener執行)
可是这个不保证 valueUpdate 二次 三次执行的顺序问题
而且 valueChangeListener 的執行會拖慢 valueUpdate 的完結
(考慮 userscript作者會利用 valueChangeListener 加一堆長時間執行的東西)
如果 valueUpdate 不等 valueChangeListener 的執行,第二次的第2個valueChangeListener 可能會較第一次的第3個 valueChangeListener 先執行
统一用 valueUpdateEventListenerEmit 的话,任何 valueUpdate 的 valueChangeListener 都要乖乖排队
这确保次序必为一致,不会插队。而且 valueUpdate 的執行不會受到 valueChangeListener 的執行而被拖慢
因為有 stackAsyncTask("valueUpdateEventListenerEmit", () => hold.promise);,所以第一個 valueChangeListener 的操作不會被立即執行,而是等 promise resolve 後的下一個 microTask
當要考慮上面所講的所有考慮,用現在這個做法是最簡單,否則寫長3倍 4倍的代碼還一堆 bug
|
唉,真的需要这么复杂的处理吗?有点看不下去 waitForFreshValueState 既然都发消息给 SW 了,为什么不直接返回要get的值 |
waitForFreshValueState 是用来等待最新值经valueUpdate 反映 如果另外处理的话,日后维护可能会令 "GM.getValue" 和 GM_getValue 的结果不一致 waitForFreshValueState 不返回值让设计灵活简单一点 |
只可能是值更新了,但是消息还没发出去到达content进行处理,才会不一致,而且这个不一致是合理的,因为GM.getValue/GM_getValue就是应该要取到最新的值,只是GM_getValue因为是同步的,可能取的并不是最新
太弯弯绕绕了 |
waitForFreshValueState 是等SW给最新的值 |
|
waitForFreshValueState 的设计是,发一个 internalApiWaitForFreshValueState 给SW,在SW那边插一个 task 到 SW valueUpdate 队列 假设 waitForFreshValueState 的发生时间是 t=4.1s, 这是相对于 setValue 要等 SW 设置后才 Promise结束 |
可以移除 waitForFreshValueState (PR其他修改不变) |
我觉得加 waitForFreshValueState 只是一个辅助。不必改变 GM.getValue 的本质。 这个修改不像 GM.setValue 那么大影响(之前 GM.setValue 会因为页面关掉而没有实际呼叫 SW 改值,影响大) |
|
我把争议大的部份先拿走,移至 #1125 |
概述 Descriptions
依存: #949
取值前确保读取的是最新 values
否则向service_worker发消息,取得最新的 valueUpdated
变更内容 Changes
截图 Screenshots
测试代码(一):
修改后:
GM.listValues()能在冲突中取得最新,而且不会因本地缓存与valueUpdate冲突而造成次序不一(
useAsync改为false的话就能看 GM_xxxx 的结果 )测试代码(二):
(有
GM_lock做时间控制)修改后GM.getValue的列表新增没问题