与Firefox附加脚本和内容脚本并发 [英] Concurrency with Firefox add-on script and content script
问题描述
当我使用附加SDK ,我注意到附加代码和内容脚本代码阻止了彼此的执行。此外,附加代码似乎甚至阻止与其他Firefox窗口(不只是选项卡)的交互。
什么是Firefox的并发/进程模型add-ons??
是否可以同时运行附加代码和内容脚本代码,而不需要合作多线程(la timers)?
加载代码加载了多少次?每个窗口一次?每个标签一次?一次?
documentation 指出:
Mozilla平台正在朝着一种模式,在这种模式下,它使用
单独的进程来显示UI,处理web内容,并执行
附加组件。主要的附加代码将在附加过程中运行,
不能直接访问任何web内容。
<所以我希望将来他们确实是一个独立的进程,不会互相干扰,但现在看来并不是这样。
更新:
我已经尝试使用附加代码中的页面工作者,但不幸的是,仍然阻止内容脚本(以及所有其他的JavaScript)。我也试着在页面工作者中使用一个web worker,但是当调用web worker的postMessage函数的时候,我得到了下面的错误。
$ b
TypeError :worker.postMessage不是一个函数
我也尝试在page-worker中创建一个iframe,然后在iframe,但不幸的是,我不能使用page-worker的window.addEventListener。我得到以下错误:
$ b
TypeError:window.addEventMessage不是函数
最后,我尝试将脚本(通过脚本元素)注入到页面工作器页面中,以创建似乎工作的web工作器。不幸的是,我不能与这个网络工作者沟通,因为我只能通过document.defaultView.postMessage发送消息给它。
哦,我正在编织纠结的网络...
content-script - > add-on - > page-worker - > iframe - > web worker - >我的代码
我已经包含一个简单的例子:
package.json
$ b $ $ name
$ b $ ,
version:0.1,
fullName:My Test Extension,
homepage:http://example.com,
id:jid1-FmgBxScAABzB2g,
description:我的测试扩展
}
lib / main.js
$ b
var data = require(self)。data;
var pageMod = require(page-mod);
$ b $ pageMod.PageMod({
include:[http:// *,https:// *],
contentScriptWhen:start,
contentScriptFile:[data.url(content.js)],
onAttach:function(worker){
worker.port.on(message,function(data){
//以繁忙循环模拟一个昂贵的操作
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);
});
//在附加代码中调用非常昂贵的操作
self.port.emit(message,{time:10000});
考虑到环境。但是,这种环境并没有出现,看起来也不会在不久的将来发生。所以你真正拥有的是在主线程(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.
这篇关于与Firefox附加脚本和内容脚本并发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!