如何在Firefox的Greasemonkey中让GM_getValue存在?

9
该问题是针对先前的GM版本的。问题可能出现在用户脚本可以运行的不同范围周围,如这里所述。然而,正如这里所述,对于Greasemonkey 4.0,此功能目前未经记录。

我有这个Greasemonkey演示脚本:

// ==UserScript==
// @name         GM_getValue, GM_setValue don't work demo
// @version      0.2
// @author       You
// @include      /^https:\/\/stackoverflow.com/$/
// @grant        GM_getValue
// @grant        GM_setValue
// @run-at       document-end
// ==/UserScript==

console.log('script started');
var id = GM_getValue('testName', 0);
console.log('got ' + id);
id++;
GM_setValue('testName', id);

将其调用为https://stackoverflow.com/,可以清楚地看到它被调用。

然而,在控制台上我得到了这个错误:

Script error:  
ReferenceError: GM_getValue is not defined
Stack trace:
userScript@user-script:demosrv/GM_getValue%2C%20GM_setValue%20don%27t%20work%20demo:372:5
scopeWrapper@user-script:demosrv/GM_getValue%2C%20GM_setValue%20don%27t%20work%20demo:381:9
@user-script:demosrv/GM_getValue%2C%20GM_setValue%20don%27t%20work%20demo:361:17

我已经查了很多文档,但似乎GM_{get,set}Value根本不存在。

为什么会这样?如何使其工作?

我正在使用Firefox浏览器。


来自未来的扩展:我最近尝试了 Tampermonkey。它在所有方面看起来都更好。它与 Greasemonkey 用户脚本兼容。 - peterh
1个回答

16

GM_getValueGM_setValue 在 GreaseMonkey 中已经过时。正确的方法是 GM.setValueGM.getValue

GreaseMonkey 文档经常使用旧的 API 调用名称,这是一个持续性的错误。可能它没有被正确更新。

如文档 这里 所述,GM 函数可以在不同的作用域中运行。不幸的是,我到现在还没找到任何信息,哪些作用域存在以及如何在它们之间切换。

所有使用 GM_getValue 的旧引用都已经过时。

重要的事情:

  • 虽然 GM_getValue 是带有返回值的函数,但是 GM.getValueGM.setValue 返回的是 Promise
  • 你几乎可以像旧版本一样使用它们,使用 await 调用。

这个远程链接上的示例可以工作:

// ==UserScript==
// @name        Greasemonkey set-and-get Example
// @description Stores and logs a counter of executions.
// @grant       GM.setValue
// @grant       GM.getValue
// ==/UserScript==

(async () => {
  let count_before = await GM.getValue('count', 0);

  // Note awaiting the set -- required so the next get sees this set.
  await GM.setValue('count', count_before + 1);

  // Get the value again, just to demonstrate order-of-operations.
  let count_after = await GM.getValue('count');

  console.log('Greasemonkey set-and-get Example has run', count_after, 'times');
})();

然而,目前关于作用域及其交互的文档仍不太清晰。

看起来至少有两种作用域:

  • 其中一种可以操作DOM,但无法访问GM.* API。
  • 另一种可以访问GM.* API(因此可以创建脚本本地的持久性存储),但无法访问DOM。
  • 在这些作用域之间,我们可以通过异步调用进行通信。
  • 为什么这会增加安全难度,甚至连GM的开发人员都可能说不清楚。

因此,开发适用于4.0版的新GreaseMonkey脚本的方法是从他们的示例脚本开始,然后遵循逐步试验和错误的路径。


扩展:我发现另一个问题:脚本中存在await似乎会导致Greasemonkey忽略整个脚本等。在示例中似乎没有出现这种情况,但在更复杂的脚本中可能会出现。我没有深入调试它 - 我只是忽略await并以旧方式使用Promises(GM.getValue("myValue").then(function(myValue) { ... });)。这使得代码更糟糕,但也无可奈何。


1
是的,我似乎无法在文档中复制他们的示例。一旦 GreaseMonkey 在脚本中看到 await 关键字,它就不会执行该脚本。这太糟糕了。 - Sudhi
@Sudhi 是的。但是,例如,这个例子是有效的。当我试图扩展它时,它突然在某个点停止工作了。我不知道为什么。也许是由于GM的用户脚本忽略功能被await存在所触发,还有另一件事情 - 我不确定是什么。 - peterh
谢谢。我也无法弄清楚。我放弃了,决定回到FirefoxESR的3.17版本。现在GM_getValue('foo', 'init');对我返回null :-/ - Sudhi
2
@Sudhi 在第二个位置上,Promise 并不那么糟糕,但我不想降低要求。所以我用 Promise 解决了这个问题,但没有使用 await。我不知道是什么原因导致这样一个受欢迎的软件维护得如此糟糕。 - peterh
3
我在这里加入一句话,感谢你确认“await”的存在会使GreaseMonkey完全忽略脚本——我确信自己一定漏掉了什么。 - scubbo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接