且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间: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.