与Firefox附加脚本和内容脚本并发

问题描述:

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

什么是Firefox附加组件的并发/过程模型?

是否可以同时运行附加代码和内容脚本代码而没有合作多线程(la定时器)?

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

documentation状态:

The Mozilla platform is moving towards a model in which it uses separate processes to display the UI, handle web content, and execute add-ons. The main add-on code will run in the add-on process and will not have direct access to any web content.

所以我希望在未来,他们确实不会互相干扰独立的过程,但是这似乎并没有被现在的情况。


更新:

我一直在使用一个页面工人从附加代码试过,但不幸的是仍然块内容脚本(以及其他所有的JavaScript)。我也尝试在页面工作者中使用web worker,但在调用web worker的postMessage函数时出现以下错误。

TypeError: worker.postMessage is not a function

我也尝试创建页面工人的iframe,然后创建在iframe一个网络工作者,但不幸的是我无法从网页工人使用window.addEventListener。我得到以下错误:

TypeError: window.addEventMessage is not a function

最后,我试着将脚本(通过脚本元素)到页面工人页面创建一个网络工作者这似乎工作。不幸的是,我无法与这位网络工作者沟通,因为我只能通过document.defaultView.postMessage发送消息给它。

哦纠结的网,我织......

内容的脚本 - >插件 - >页面工人 - > IFRAME - >网络工作者 - >我的代码


我已经包括一个简单的例子:

的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!' }); 
     }); 
    } 
}); 

数据/内容。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 }); 

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

Is it possible to run add-on code and content script code concurrently without cooperative multithreading (a la timers)?

是的,你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"]; 

How many times is the add-on code loaded? Once per window? Once per tab? Once?

如果您询问附加代码:只要加载项处于活动状态,它将只加载一次并保持在附近。至于内容脚本,脚本注入的每个文档都有一个单独的实例。

+0

这似乎并不奏效。如果我尝试在附加代码中创建一个web worker,那么它会显示_ReferenceError:Worker不是defined_。如果我尝试在内容脚本中创建web worker,那么它会显示_ReferenceError:webWorker.addEventListener不是函数_。 – fixedpoint 2012-02-10 08:08:46

+0

@ user967974:是的,在查看一些附加SDK的讨论之后,看起来网络工作者还没有真正受到支持。我用黑客更新了我的答案,但仍然可以使用它们。 – 2012-02-10 09:14:57

+0

这似乎工作,但有一个奇怪的警告。我无法将postMessage中的对象传递给worker。它引发异常_该对象无法克隆_。当然,我可以使用JSON序列化对象,然后将字符串传输给工作人员。谢谢。 – fixedpoint 2012-02-10 10:28:32

我发现一个黑客获得WebWorkers在扩展的背景页:

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变通办法垃圾,似乎工作得很好。