更新时间:2023-12-05 18:15:52
考虑到环境。但是,这种环境并没有出现,看起来也不会在不久的将来发生。所以你真正拥有的是在主线程(UI线程)上的同一进程中运行的加载项和内容脚本。这就意味着一次只能运行其中的一个,因为你已经注意到没有并发。
是否可以运行附加代码和内容脚本代码并发,没有合作多线程(定时器)?
是的,你使用网络工作者(与 page-worker
模块,尽管类似的名字)。对于昂贵的操作,这通常是值得推荐的 - 你不希望你的插件在做某事的时候停止对消息的响应。不幸的是,附加SDK没有正确公开Web工作,所以我不得不使用建议的 here : $ b
worker.port.on(message,function(message){
//从JavaScript模块获取工作类并立即卸载它
var {Cu} = require(chrome);
var {Worker} = Cu.import(data.url(dummy.jsm));
Cu.unload(data.url(dummy.jsm));
$ 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];
加载代码加载了多少次?每个窗口一次?每个标签一次?一次?
如果您询问附加代码,只需加载一次,只要加载项活跃。至于内容脚本,注入脚本的每个文档都有一个单独的实例。
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 });
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.
Is it possible to run add-on code and content script code concurrently without cooperative multithreading (a la timers)?
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:
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);
});
The JavaScript module data/dummy.jsm
only contains a single line:
var EXPORTED_SYMBOLS=["Worker"];
How many times is the add-on code loaded? Once per window? Once per tab? Once?
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.