Skip to content

Conversation

@cyfung1031
Copy link
Collaborator

概述 Descriptions

异歩 GM.getValue/getValues/listValues 修正

变更内容 Changes

增加内部函数 GM_waitForFreshValueState, 会传最新的 scriptRes.updatetime
若valueUpdate未触发,把Promise加至readFreshes进行等待

截图 Screenshots

@cyfung1031
Copy link
Collaborator Author

// ==UserScript==
// @name         Save Page URL to List
// @namespace    yourname.scripts
// @version      3.0
// @description  把当前网页URL保存到存储列表中
// @author       You
// @match        *://*/*
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.deleteValue
// @grant        GM.listValues
// @grant        GM_addValueChangeListener
// @grant        GM_removeValueChangeListener
// @require      https://update.greasyfork.org/scripts/554436/1687655/GM_lock.js
// ==/UserScript==

/* global GM_lock */
(function () {
    'use strict';
    console.log("载入了", Date.now(), performance.now());
    GM_lock("lock_urls", async () => {
        console.log("开始", Date.now(), performance.now());
        // 等一下这个页面SC的缓存更新
        // await new Promise(resolve=>setTimeout(resolve, 50));
        // 从存储中读取已有的列表
        let list = await GM.getValue('list', []); // 设置默认值为空数组
        // 如果当前URL不在列表中,就添加进去
        console.log("初始列表:", list.slice());
        if (!list.includes(location.href)) {
            list.push(location.href);
            await GM.setValue('list', list);
            console.log('✅ 已保存此页面到列表:', location.href);
        } else {
            console.log('ℹ️ 当前页面已在列表中');
        }
        // 可选:在控制台查看当前列表
        console.log('当前列表:', list.slice());
        // 等一下其他页面SC的缓存更新
        // await new Promise(resolve=>setTimeout(resolve, 50));
        console.log("结束", Date.now(), performance.now());
    });
    if (window.location.href.includes("scriptcat.org/zh-CN")) {
        window.open("https://docs.scriptcat.org/docs/use");
        window.open("https://bbs.tampermonkey.net.cn/");
    }
})();
Screenshot 2025-11-02 at 16 39 56

@cyfung1031 cyfung1031 force-pushed the pr-get-list-value-lock branch from a123e26 to 04d6641 Compare November 6, 2025 11:43
@CodFrm CodFrm changed the base branch from main to release/v1.3 November 8, 2025 02:31
@CodFrm CodFrm requested a review from Copilot November 8, 2025 02:31
Copy link
Contributor

Copilot AI left a 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 为 GM.getValue、GM.listValues 和 GM.getValues 等异步 API 添加了数据同步机制,确保这些 API 在读取值之前能获取到最新的数据库状态。

主要变更:

  • 在 ValueService 中添加 updatetime 字段跟踪,记录每次值更新的时间戳
  • 实现 GM_waitForFreshValueState API,用于获取最新的 updatetime
  • 修改 GM.getValue、GM.listValues、GM.getValues 等异步 API,在读取前等待数据同步到最新状态

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/app/service/service_worker/value.ts 在 setValue 和 setValues 方法中添加 updatetime 跟踪逻辑,新增 waitForFreshValueState 方法
src/app/service/service_worker/gm_api.ts 添加 GM_waitForFreshValueState API 处理函数
src/app/service/content/types.ts 在 ValueUpdateDataEncoded 类型中添加 updatetime 字段
src/app/service/content/gm_api.ts 实现 waitForFreshValueState 函数,修改 GM.getValue、GM.listValues、GM.getValues 使用该函数;修正一处注释的繁体字
src/app/service/content/gm_api.test.ts 添加 valueDaoUpdatetimeFix 辅助函数,更新测试以支持新的同步机制;修正正则表达式匹配模式

Comment on lines 337 to 347
async GM_waitForFreshValueState(request: GMApiRequest<[boolean]>, sender: IGetSender) {
const param = request.params;
if (param.length !== 1) {
throw new Error("there must be one parameter");
}
const ret = await this.value.waitForFreshValueState(request.script.uuid, {
runFlag: request.runFlag,
tabId: sender.getSender()?.tab?.id || -1,
});
return ret;
}
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

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

GM_waitForFreshValueState 函数接收的参数声明为 GMApiRequest<[boolean]>,并验证参数长度必须为 1,但实际上并未使用该参数。在 content/gm_api.ts:255 调用时传递的是 [true],但在函数内部完全没有使用 request.params[0]。要么应该使用该参数,要么应该将类型改为 GMApiRequest<[]> 并移除长度验证。

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

之前好像不放东西的话,传送有问题。我没有看到其他没用param的API。
所以就放一个 true 了
先这样吧

@cyfung1031 cyfung1031 marked this pull request as draft November 9, 2025 02:32
@cyfung1031
Copy link
Collaborator Author

研究一下效能提升。先轉 draft

@cyfung1031 cyfung1031 force-pushed the pr-get-list-value-lock branch from 35d670e to 79ad4e2 Compare November 9, 2025 05:00
@cyfung1031 cyfung1031 force-pushed the pr-get-list-value-lock branch from 7eb600c to 035ce3d Compare November 9, 2025 10:47
@cyfung1031 cyfung1031 marked this pull request as ready for review November 10, 2025 10:45
@cyfung1031
Copy link
Collaborator Author

@CodFrm 改好了

测试代码(一):

修改后:GM.listValues() 能在冲突中取得最新,而且不会因本地缓存与valueUpdate冲突而造成次序不一

// ==UserScript==
// @name         测试 GM.getValue 能否取得最新值
// @namespace    yourname.scripts
// @version      0.1.0
// @description  把当前网页URL保存到存储列表中
// @author       You
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.deleteValue
// @grant        GM.listValues
// @grant        GM_addValueChangeListener
// @grant        GM_removeValueChangeListener
// ==/UserScript==

(function () {
    'use strict';
    let useAsync = true;
    const rid = `${(Math.floor(Math.random() * 5000) + 4000).toString(36)}`;

    const trigger = async () => {
        console.log(`[${rid}]`,"trigger in " + location.href, "current time = " + Date.now());
        useAsync ? action2() : action1();
    }
    let k = 0;
    const action1 = async () => {
        ++k;
        GM_setValue(`${"list_"}${rid}${k}`, Date.now());
        console.log(`[${rid}]`, GM_listValues());
    };

    const action2 = async () => {
        ++k;
        await GM.setValue(`${"list_"}${rid}${k}`, Date.now());
        console.log(`[${rid}]`, await GM.listValues());
    };

    const wins = [];
    let tc0;
    window.addEventListener("message", (e) => {
        if (e.data && typeof e.data === "object" && e.data?.test_call_id && e.data?.type === "response_tc") {
            const tc1 = e.data.test_call_id;
            if (tc1 === tc0) {
                trigger();
            }
        }
    });
    if (location.search.startsWith("?test_call=") && top !== window) {
        const usp = new URLSearchParams(location.search);
        const tc = usp.get("test_call");
        if (tc) {
            tc0 = tc;
            window.top.postMessage({ type: "done_iframe_tc", test_call_id: tc }, "*");
        }
    } else if (window.location.href.includes("example.com") && top === window) {
        const test_call_id = `tc${Date.now()}_${Math.random()}`;
        tc0 = test_call_id;
        let q = 1;
        let ec = 0;
        const doFunc = async (elements) => {
            console.log(`[${rid}]`,"---- ADD SOME INFO... ------");
            await (useAsync ? action2() : action1());
            await (useAsync ? action2() : action1());
            await (useAsync ? action2() : action1());
            console.log(`[${rid}]`,"---------------------------");
            setTimeout(() => {
                console.log(`[${rid}]`,"do trigger");
                for (const iframe of elements) {
                    try {
                        iframe.contentWindow.postMessage({ type: "response_tc", test_call_id },
                            "*"
                        )
                    } catch (e) {
                        // ignored
                    }
                }
                window.postMessage({ type: "response_tc", test_call_id }, "*");

                setTimeout(async () => {
                     console.log(`[${rid}]`,"final list", await GM.listValues());
                }, 1500)
            }, 1500);
        }
        window.addEventListener("message", (e) => {
            if (e.data && typeof e.data === "object" && e.data?.test_call_id && e.data?.type === "done_iframe_tc") {
                const tc = e.data.test_call_id;
                if (tc === test_call_id) {
                    const elements = document.querySelectorAll("iframe.tt0011");
                    // wins.push([e.source, e.origin]);
                    wins.push(1);
                    if (wins.length === elements.length && elements.length === ec && q) {
                        q = 0;
                        doFunc(elements);
                    }
                }
            }
        });
        
        const makeIframe = () => {
            const elm = document.body.appendChild(document.createElement("iframe"));
            elm.classList.add("tt0011");
            return elm;
        }

        ec = 3;
        setTimeout(()=>{

            makeIframe().src = `https://example.com/?test_call=${test_call_id}`;
        }, 1800);

        setTimeout(()=>{

            makeIframe().src = `https://example.com/?test_call=${test_call_id}`;
        }, 2400);

        setTimeout(() => {
            makeIframe().src = `https://example.com/?test_call=${test_call_id}`;
        }, 3200);
    }
})();

测试代码(二):

(有GM_lock 做时间控制)修改后 GM.getValue 的列表新增没问题

// ==UserScript==
// @name         Example Script for GM_lock
// @namespace    yourname.scripts
// @version      0.1
// @description  把当前网页URL保存到存储列表中
// @author       You
// @match        *://*/*
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.setValues
// @grant        GM.deleteValue
// @grant        GM.deleteValues
// @grant        GM.listValues
// @grant        GM_addValueChangeListener
// @grant        GM_removeValueChangeListener
// @require      https://update.greasyfork.org/scripts/554436/1692608/GM_lock.js
// @noframes
// ==/UserScript==

/* global GM_lock */
(function () {
  'use strict';
  GM_lock("lock_urls", async () => {
    console.log("开始", Date.now(), performance.now());
    // 等一下这个页面SC的缓存更新
    // await new Promise(resolve => setTimeout(resolve, 50));
    // 从存储中读取已有的列表
    let list = await GM.getValue('list', []); // 设置默认值为空数组
    // 如果当前URL不在列表中,就添加进去
    console.log("初始列表:", list.slice());
    if (!list.includes(location.href)) {
      list.push(location.href);
      await GM.setValue('list', list);
      console.log('✅ 已保存此页面到列表:', location.href);
    } else {
      console.log('ℹ️ 当前页面已在列表中');
    }
    // 可选:在控制台查看当前列表
    console.log('当前列表:', list.slice());
    // 等一下其他页面SC的缓存更新
    // await new Promise(resolve => setTimeout(resolve, 50));
    console.log("结束", Date.now(), performance.now());
  });
})();

@cyfung1031
Copy link
Collaborator Author

#936 有关连的改动。 我先开一个 分支 develop/raw-message 处理一下。

@cyfung1031 cyfung1031 marked this pull request as draft November 10, 2025 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

GM API 支持一下TM/VM/FM的API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant