Greasemonkey: WebExt:在所有三个 runAt 时间执行脚本

创建于 2017-02-27  ·  6评论  ·  资料来源: greasemonkey/greasemonkey

想出一个如何执行用户脚本的工作计划,当然直到运行时才知道。 与所有三个 runAt 时间兼容——尤其是document_start

到目前为止,我的研究见https://github.com/arantius/greasemonkey/tree/8a255bde1aa6312715740fd0157d582a2d6cb183 ,方法是:

  • 使用一个后台脚本。 (它将可以访问存储/任何 API,存储脚本的位置,因此可以知道要执行的脚本的内容。)
  • 观察某事(什么? )来触发..
  • .. 调用tabs.executeScript()来触发每个用户脚本。

这个“有效”,除了我还没有发现可以观察到对所有三个运行时间都有效的事件。 有webNavigationonBeforeNavigate实际上太早了,它(顾名思义)在导航之前触发,当当前文档仍然处于活动状态时。 但是下一点是onCommitted ,此时开始为时已晚,内联脚本已经执行。

wontfix

所有6条评论

研究:

  • 观察webRequest而不是webNavigation 。 这是否在开始时为我们提供了一个句柄?
  • 在 document_start 为每个页面注入一个 webext 内容脚本。 让它以某种方式知道要同步执行哪些脚本。 (因为任何异步都会使我们超过开始时间。)

回复: https :

我希望能够(在后台)存储一个 blob,稍后获取(仅)它的 URL 并将该 URL(同步)传递给内容脚本,但我知道无法做任何这些事情。

我自己还没有弄清楚所有的细节,但我认为后台页面可以将 blob 存储在 IndexedDB 中,然后在启动时通过 URL.createObjectURL() 将它们转换为 blob URI,并将它们传递给假设的同步配置 API,然后也许通过加载它们

在 Firefox 的隐私浏览模式下,IndexedDB 不是被

我认为这不会影响后台脚本?

这可以通过使用在document_start运行的内容脚本来实现,看起来像这样:(可能不适用于已经加载的选项卡,为此使用 jQuery)

// execute `document_start` scripts here...

document.addEventListener("DOMContentLoaded", event => {
    // execute `document_end` scripts here...
});

window.addEventListener("load", event => {
    // execute `document_idle` scripts here...
});

或类似的东西:(可能更容易出错)

let run = [false, false, false];

document_start();

if (document.readyState === "complete") {
    document_idle();
} else if (document.readyState === "interactive") {
    document_end();
}

document.onreadystatechange = () => {
    switch (document.readyState) {
        case "loading":     break;
        case "interactive": document_end();
        case "complete":    document_idle();
    }
};

function document_start() {
    if (run[0]) return;
    run[0] = true;

    // execute `document_start` scripts here...
}

function document_end() {
    if (!run[0]) document_start();
    if (run[1])  return;
    run[1] = true;

    // execute `document_end` scripts here...
}

function document_idle() {
    if (!run[1]) document_end();
    if (run[2])  return;
    run[2] = true;

    // execute `document_idle` scripts here...
}

另一种方法是使用三个单独的内容脚本,其中每个脚本在不同的时间运行。
为此, manifest.json包含以下内容:(保证可能有效(可能存在竞争条件))

"content_scripts": [
    {
        "matches": ["<all_urls>"],
        "run_at": "document_start",
        "js": ["document_start_handler.js"]
    },
    {
        "matches": ["<all_urls>"],
        "run_at": "document_end",
        "js": ["document_end_handler.js"]
    },
    {
        "matches": ["<all_urls>"],
        "run_at": "document_idle",
        "js": ["document_idle_handler.js"]
    }
]

也可以使用 jQuery,这可能是最不容易出错的方式,但这都需要大量测试:(同样,以document_start运行,但需要与 jQuery 捆绑在一起)

function document_start() {
    // execute `document_start` scripts here...
}

function document_end() {
    // execute `document_end` scripts here...
}

function document_idle() {
    // execute `document_idle` scripts here...
}

// Use jQuery to execute all the functions:
document_start();

// `$(document).ready(document_end)` is deprecated since 3.0
$(document_end);

// jQuery used to have a method for this: `$(window).load(document_idle)`
if (document.readyState === "complete") {
    document_idle();
} else {
    $(window).on("load", document_idle);
}

正如所写,这个问题太广泛了。 我将其拆分为单独的问题,以便更轻松地进行跟踪:

2525,#2526

此页面是否有帮助?
0 / 5 - 0 等级