【问题标题】:Converting external sync function to behave as async将外部同步功能转换为异步
【发布时间】:2020-12-03 04:50:49
【问题描述】:

这是一个集思广益的问题,正在寻找想法。

是否有任何方法可以将外部脚本中的同步函数转换为异步。

考虑用户脚本和用户脚本管理器的情况。

用户脚本使用同步GM_getValue 函数,用户脚本开发人员不愿意将代码更新为异步GM.getValue API。

正在处理脚本的脚本管理器,不支持同步方式。

有没有办法以异步方式处理代码?

例子:

function run() {

  const a = GM_getValue('one');
}
  • 是否有可能通过脚本管理器暂停该函数,直到异步响应可用?
  • 有没有办法解析脚本并将相关函数转换为async/await? (正则表达式容易出错)
  • 有没有办法覆盖该函数并将其替换为异步版本?
    例如
async function run() {

  const a = await GM_getValue('one');
}
  • 还有其他想法吗?

在 cmets 之后更新示例

// ==UserScript==
// @name            My Script
// @match           http://www.example.org/*
// @grant           GM_getValue
// ==/UserScript==

function run() {
  const b = GM_getValue("one"); 
  if (b && b > a) {
    // do somthig
  }
  else {
    // do something else
  }
  return b;
}

const a = 5;
const c = run();
const d = GM_getValue("two"); 
const e = parseInt(d);

if (d > a) {
  // do somthig
}
else {
  // do something else
}

function sum(a, b) {
  return a + b;
}

const f = sum(2, 5);

【问题讨论】:

  • async function run() { const a = await GM_getValue('one'); } 有什么问题?
  • @FZs 用户脚本代码不受脚本管理器控制。

标签: javascript


【解决方案1】:

脚本管理器是否有可能在异步响应可用之前暂停该功能?

没有。最接近的应该是同步 XHR,但它已被弃用,应该避免。

没有简单的一刀切解决方案。一个正则表达式肯定是不够的。你要么必须:

  • 浏览脚本,确定需要异步的 API 的所有用途,并重构控制流以解决问题。虽然这可能有点乏味,但它相当死记硬背,对于有使用该语言经验的人来说应该很容易。

  • 改用不同的同步方法。这是我更喜欢的。不要使用GM_getValue,而是考虑将用户脚本设置保存在本地存储中。这通常是一个不错的选择,除非数据是敏感的并且该站点是不可信的。例如,而不是

    const a = GM_getValue('one');
    

    你可以的

    const userscriptSettings = JSON.parse(localStorage.userscriptSettings || '{}');
    const a = userscriptSettings.a;
    

有时本地存储是不够的,例如saving huge amounts of data 时,或者保存站点具有理论更改能力的数据是值得担心的,在这种情况下,您将不得不采取其他选项涉及异步控制流重构。

对于问题中的示例,我将其更改为:

const runScript = (userscriptSettings) => {
  function run() {
    const b = userscriptSettings.one;
    // ...
  }
  const a = 5;
  const c = run();
  const d = userscriptSettings.two;
  // ...
};
Promise.all([
  GM.getValue('one'),
  GM.getValue('two'),
])
  .then(([one, two]) => runScript({ one, two }));

【讨论】:

  • localStorage 是不可能的,因为用户脚本可以在多个域上运行,并且将保存到单个域,并且数据在其他域中不可用。
  • 您可以决定将设置保存到单个域,然后由用户脚本控制communicate between the domains with a hidden iframe。这很挑剔,但it's an option 如果您不想走异步重构路线。
  • 使用隐藏 iframe 在域之间进行通信是一种异步方法(postMessage + addEventListener)。
  • 哦,对了。如果您需要跨域存储,那么您似乎必须进行异步重构。但在大多数情况下,这应该很容易:只需更改入口点以获取用户脚本设置,然后运行其余代码,其余部分不做任何更改。
  • 整个问题是原来的功能是同步;)
猜你喜欢
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多