scriptcat icon indicating copy to clipboard operation
scriptcat copied to clipboard

[v1.3] 異步 getValue/getValues/listValues 相关修改

Open cyfung1031 opened this issue 1 month ago • 2 comments

概述 Descriptions

依存: #949

  • #898 取值前确保读取的是最新 values 否则向service_worker发消息,取得最新的 valueUpdated
  • #943
  • 这个可以单独合并到 main. 只是避免合并问题,一并提交到同一个PR

变更内容 Changes

截图 Screenshots


测试代码(一):

修改后:GM.listValues() 能在冲突中取得最新,而且不会因本地缓存与valueUpdate冲突而造成次序不一 ( useAsync 改为 false 的话就能看 GM_xxxx 的结果 )


// ==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 avatar Nov 14 '25 03:11 cyfung1031

怎么都到这个分支去了 develop/raw-message

CodFrm avatar Nov 15 '25 04:11 CodFrm

怎么都到这个分支去了 develop/raw-message

因为两边的 commit 互相影响 但处理的内容不一样,写在同一PR又太多又乱

cyfung1031 avatar Nov 15 '25 07:11 cyfung1031