【问题标题】:Concurrency with Firefox add-on script and content script与 Firefox 插件脚本和内容脚本的并发性
【发布时间】:2012-02-09 18:55:07
【问题描述】:

当我使用 Add-on SDK 编写 Firefox 插件时,我注意到插件代码和内容脚本代码会阻止彼此的执行。此外,附加代码似乎甚至阻止了与其他 Firefox 窗口(不仅仅是选项卡)的交互。

Firefox 插件的并发/进程模型是什么?

是否可以同时运行附加代码和内容脚本代码而无需协作多线程(例如计时器)?

插件代码加载了多少次?每个窗口一次?每个标签一次?一次?

documentation 声明:

Mozilla 平台正在朝着它使用的模型迈进 用于显示 UI、处理 Web 内容和执行的单独进程 附加组件。主插件代码将在插件进程中运行,并将 无法直接访问任何网页内容。

所以我希望将来它们确实是独立的进程,不会相互干扰,但现在似乎并非如此。


更新:

我已经尝试使用附加代码中的页面工作者,但不幸的是,它仍然会阻止内容脚本(以及所有其他 javascript)。我也尝试在 page-worker 中使用 web worker,但是在调用 web worker 的 postMessage 函数时出现以下错误。

TypeError: worker.postMessage 不是函数

我还尝试在 page-worker 中创建一个 iframe,然后在 iframe 中创建一个 web worker,但不幸的是我无法使用 page-worker 中的 window.addEventListener。我收到以下错误:

TypeError: window.addEventMessage 不是函数

最后,我尝试将脚本(通过 script 元素)注入到 page-worker 页面中,以创建一个似乎可以工作的 web worker。不幸的是,我无法与这个网络工作者交流,因为我只能通过 document.defaultView.postMessage 向它发送消息。

哦,我正在编织的纠结的网......

content-script -> add-on -> page-worker -> iframe -> web worker -> 我的代码


我举了一个简单的例子:

package.json

{
    "name": "test", 
    "author": "me", 
    "version": "0.1", 
    "fullName": "My Test Extension", 
    "homepage": "http://example.com", 
    "id": "jid1-FmgBxScAABzB2g", 
    "description": "My test extension"
}

lib/main.js

var data = require("self").data;
var pageMod = require("page-mod");

pageMod.PageMod({
    include: ["http://*", "https://*"],
    contentScriptWhen: "start",
    contentScriptFile: [data.url("content.js")],
    onAttach: function (worker) {
        worker.port.on("message", function (data) {
            // simulate an expensive operation with a busy loop
            var start = new Date();
            while (new Date() - start < data.time);
            worker.port.emit("message", { text: 'done!' });
        });
    }
});

data/content.js

self.port.on("message", function (response) {
    alert(response.text);
});

// call a very expensive operation in the add-on code
self.port.emit("message", { time: 10000 });

【问题讨论】:

    标签: firefox-addon firefox-addon-sdk


    【解决方案1】:

    消息传递系统的设计考虑了多进程环境。但是,这种环境并没有出现,而且看起来在不久的将来也不会出现。因此,您真正拥有的是在主线程(UI 线程)上的同一进程中运行的附加组件和内容脚本。这意味着一次只有一个在运行,因为您已经注意到没有并发。

    是否可以在没有协作多线程(例如计时器)的情况下同时运行附加代码和内容脚本代码?

    是的,你 use web workers(尽管名称相似,但与 page-worker 模块无关)。对于昂贵的操作,这通常是值得推荐的——你不希望你的插件在它做某事时停止响应消息。不幸的是,附加 SDK 没有正确公开网络工作者,所以我不得不使用建议的解决方法here

    worker.port.on("message", function (message) {
        // Get the worker class from a JavaScript module and unload it immediately
        var {Cu} = require("chrome");
        var {Worker} = Cu.import(data.url("dummy.jsm"));
        Cu.unload(data.url("dummy.jsm"));
    
        var webWorker = new Worker(data.url("expensiveOperation.js"));
        webWorker.addEventListener("message", function(event)
        {
          if (event.data == "done")
            worker.port.emit("message", { text: 'done!' });
        }, false);
    });
    

    JavaScript 模块data/dummy.jsm 只包含一行:

    var EXPORTED_SYMBOLS=["Worker"];
    

    加载项代码加载了多少次?每个窗口一次?每个标签一次?一次?

    如果您询问的是插件代码:它只加载一次,并且只要插件处于活动状态就会一直存在。至于内容脚本,每个注入脚本的文档都有一个单独的实例。

    【讨论】:

    • 这似乎不起作用。如果我尝试在附加代码中创建一个 web worker,那么它会显示 ReferenceError: Worker is not defined。如果我尝试在内容脚本中创建一个网络工作者,那么它会说 ReferenceError: webWorker.addEventListener is not a function.
    • @user967974:是的,在查看了一些关于附加 SDK 的讨论之后,似乎还没有真正支持网络工作者。我用一个黑客更新了我的答案,让你仍然可以使用它们。
    • 这似乎可行,但有一个奇怪的警告。我无法将 postMessage 中的对象传递给工作人员。它抛出异常无法克隆对象。当然,我可以用 JSON 序列化对象,然后将字符串传输给 worker。谢谢。
    • @user967974: postMessage 仅接受 JSON 可序列化对象,每当您尝试向其提供没有 JSON 表示的内容时,就会出现此消息。再说一遍,可能存在范围问题(您从中获得 Worker 的 JS 模块有自己的范围,有自己的 ObjectArray 类),您确实必须手动使用 JSON 序列化。
    【解决方案2】:

    我在扩展程序的后台页面中找到了获取 WebWorkers 的 hack:

    if(typeof(Worker) == 'undefined')
    {
        var chromewin   =   win_util.getMostRecentBrowserWindow();
        var Worker      =   chromewin.Worker;
    }
    var worker      =   new Worker(data.url('path/to/script.js'));
    

    通过访问主窗口的window 对象,您可以将Worker 类拉入当前范围。这解决了所有令人讨厌的 Page.Worker 解决方法垃圾问题,并且似乎工作得相当好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-12
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多