与 Firefox 附加脚本和内容脚本的并发
当我使用 附加SDK,我注意到附加代码和内容脚本代码会互相阻塞执行。此外,附加代码似乎甚至阻止了与其他 Firefox 窗口(不仅仅是选项卡)的交互。
Firefox 附加组件的并发/进程模型是什么?
是否可以在没有协作多线程(定时器)的情况下同时运行附加组件代码和内容脚本代码?
附加代码加载了多少次?每个窗口一次?每个选项卡一次?一次?
文档指出:
Mozilla 平台正在走向一种使用它的模型 单独的进程来显示 UI、处理 Web 内容和执行 附加组件。主要的附加代码将在附加进程中运行,并将 无法直接访问任何网络内容。
所以我希望将来它们确实是独立的进程,不会互相干扰,但现在情况似乎并非如此。
更新:
我尝试使用附加代码中的页面工作人员,但不幸的是,这仍然阻止内容脚本(以及所有其他 JavaScript)。我还尝试在页面工作人员中使用网络工作人员,但在调用网络工作人员的 postMessage 函数时出现以下错误。
类型错误:worker.postMessage 不是函数
我也尝试在页面工作人员中创建一个 iframe,然后在 iframe 中创建一个网络工作人员,但不幸的是我无法从页面工作人员中使用 window.addEventListener。我收到以下错误:
类型错误:window.addEventMessage 不是函数
最后,我尝试将脚本(通过 script 元素)注入到 page-worker 页面中,以创建一个似乎可以工作的 Web Worker。不幸的是,我无法与这个网络工作者通信,因为我只能通过 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!' });
});
}
});
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 });
As I was writing a Firefox add-on using the Add-on SDK, I noticed that the add-on code and the content script code block the execution of each other. Furthermore, the add-on code seems even to block the interaction with other Firefox windows (not just tabs).
What is the concurrency/process model of Firefox add-ons?
Is it possible to run add-on code and content script code concurrently without cooperative multithreading (a la timers)?
How many times is the add-on code loaded? Once per window? Once per tab? Once?
The documentation states:
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.
So I hope that in the future that they are indeed separate processes that will not interfere with each other, but that doesn't seem to be the case now.
Update:
I have tried using a page-worker from the add-on code, but unfortunately that still blocks the content script (as well as all other javascript). I also tried using a web worker in the page-worker, but I get the following error when calling the web worker's postMessage function.
TypeError: worker.postMessage is not a function
I also tried creating an iframe in the page-worker and then creating a web worker in the iframe, but unfortunately I cannot use window.addEventListener from the page-worker. I get the following error:
TypeError: window.addEventMessage is not a function
Finally, I tried to inject script (via script element) into the page-worker page to create a web worker which does seem to work. Unfortunately, I cannot communicate with this web worker because I can only send messages to it via document.defaultView.postMessage.
Oh the tangled webs I am weaving...
content-script -> add-on -> page-worker -> iframe -> web worker -> my code
I have included a simple example:
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 });
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
消息传递系统在设计时考虑了多进程环境。不过这个环境并没有出现,看来近期也不会出现。因此,您真正拥有的是在主线程(UI 线程)上的同一进程中运行的附加组件和内容脚本。这意味着一次只有其中一个正在运行,正如您已经注意到的那样,没有并发性。
是的,您使用网络工作人员(与
page-worker< /code> 模块,尽管名称相似)。对于昂贵的操作,这通常是推荐的 - 您不希望您的附加组件在执行某些操作时停止响应消息。不幸的是,附加 SDK 无法正确公开网络工作人员,因此我不得不使用建议的解决方法 此处:
JavaScript 模块
data/dummy.jsm
仅包含一行:如果您询问附加组件代码:它仅加载一次,并且只要附加组件处于活动状态,它就会一直存在。至于内容脚本,注入脚本的每个文档都有一个单独的实例。
The messaging system has been designed with a multi-process environment in mind. However, this environment didn't emerge and it looks like it won't happen in near future either. So what you really have is both the add-on and the content script running in the same process on the main thread (UI thread). And that means that only one of them is running at a time, as you already noticed there is no concurrency.
Yes, you use web workers (that have nothing to do with the
page-worker
module despite a similar name). This would be generally recommendable for expensive operations - you don't want your add-on to stop responding to messages while it is doing something. Unfortunately, the Add-on SDK doesn't expose web workers properly so I had to use the work-around suggested here:The JavaScript module
data/dummy.jsm
only contains a single line:If you are asking about add-on code: it is loaded only once and stays around as long as the add-on is active. As to content scripts, there is a separate instance for each document where the script is injected.
我发现了一个在扩展的后台页面中获取 WebWorkers 的技巧:
通过访问主窗口的
window
对象,您可以将Worker
类拉入当前范围。这绕过了所有令人讨厌的Page.Worker
解决方法垃圾,并且似乎工作得相当好。I found a hack to get WebWorkers in the extension's background page:
By accessing the main window's
window
object, you can pull theWorker
class into the current scope. This gets around all the obnoxiousPage.Worker
workaround junk and seems to work fairly well.