When do I load a browser frame script (e10s)?

298 Views Asked by At

I'm trying to port one of my Firefox extensions to support Electrolysis (e10s). My extension grabs some page data and puts it on the clipboard via a context-menu item that the user can click. Based on the message manager documentation, there are 3 types of message managers available:

  1. Global
  2. Window
  3. Browser

Since my add-on is context specific, the last one seems like the one I want to use. The problem is that I don't fully know when to load the frame script. A simplified version of my context menu item's action handling code looks like this:

onContext: function() {
  let browserMM = gBrowser.selectedBrowser.messageManager;
  browserMM.loadFrameScript("chrome://myaddon/content/frame-script.js", true);
  browserMM.sendAsyncMessage("[email protected]:get-page-info", json);
}

Loading the frame script here seemed like the best idea to me since (a) the frame script isn't guaranteed to get used on every page and (b) I figured that frame scripts are loaded once and only once per <browser>. The second theory isn't correct it seems; each time I call loadFrameScript, a new copy gets loaded. Even load-protection logic (i.e. only creating the frame script functions if they don't already exist) doesn't seem to fix the problem.

So, my problem is that each time the context menu item is accessed, a new copy of the frame script gets loaded. And since my frame script adds a message listener, I get duplicate messages on subsequent calls of the context menu item.

When should I load browser frame scripts? Loading it once on add-on initialization doesn't seem to work well, since it only loads on the first <browser> (I want this code to execute when asked for by any subsequent <browser>). But loading it on demand appears to duplicate things.

Are there other strategies I'm missing here?

1

There are 1 best solutions below

2
On BEST ANSWER

Even load-protection logic (i.e. only creating the frame script functions if they don't already exist)

Frame scripts are a bit tricky, scripts for each tab share a global object but have a separate scope, akin to being evaluated inside their own function block. So if you add it multiple times to a tab then each gets evaluated in a separate scope.

Instead you might want to track the browser objects that already have your frame script attached with a WeakMap. Although I think there also is some property to enumerate the loaded frame scripts.

Loading it once on add-on initialization doesn't seem to work well

If you want that, then use the global message manager and attach a delayed frame script, that'll get attached to all current and future tabs. Of course that will consume more memory than just attaching it to tabs that really need it.

browserMM.loadFrameScript("chrome://myaddon/content/frame-script.js", true);

You don't really need to set the delayed flag to true if you run it on a specific browser, that only makes sense for broadcasting message manager which may get additional children in the future.