Frame script loading and lifetime

This article needs a technical review. How you can help.

This article needs an editorial review. How you can help.

Loading frame scripts

To load a frame script use the loadFrameScript() function.

This line of code loads a frame script into the currently selected tab. The frame script just write "foo" to the command line:

// chrome script
var mm = gBrowser.selectedBrowser.messageManager;
mm.loadFrameScript('data:,dump("foo\n")', true);

loadFrameScript() takes two mandatory parameters:

  • a URL pointing to the frame script you want to load.
  • a boolean flag allowDelayedLoad

Extension developers can use a "chrome.manifest" file to register a chrome URL. This defines the mapping between the chrome:// URL and a frame script packaged with the extension:

// chrome.manifest
content my-e10s-extension content.js
// chrome script
mm.loadFrameScript("chrome://my-e10s-extension/content/content.js", true);

Note that if the message manager is a ChromeMessageBroadcaster (for example, a global frame message manager or a window message manager) then loadFrameScript() may load the script multiple times, once into each applicable frame.

allowDelayedLoad

If the message manager is a ChromeMessageBroadcaster (for example, a global frame message manager or a window message manager) then:

  • if allowDelayedLoad is true, the frame script will be loaded into any new frames opened after the loadFrameScript() call. For example:

    var mm = window.messageManager;
    mm.loadFrameScript("chrome://my-e10s-extension/content/frame-script.js", true);

    The script will be loaded into all tabs currently open in this window, and into any new tabs opened afterwards.

  • if allowDelayedLoad is false, then the script will only be loaded into frames that are open when the call is made.

If the message manager is a browser message manager, you should just always pass true here. Because a browser message manager only ever corresponds to a single browser tab, its loadFrameScript() function will only ever load the frame script into that one tab. So passing allowDelayedLoad is just a way to ensure that the script gets loaded properly, in case the tab is not ready when you make the call.

If you use allowDelayedLoad, with a ChromeMessageBroadcaster, you can cancel it using removeDelayedFrameScript:

var mm = window.messageManager;
mm.removeDelayedFrameScript("chrome://my-e10s-extension/content/frame-script.js");

This means that we will stop loading the script into new tabs. Note that this function will not remove any scripts that have already been loaded.

Frame script lifetime

Frame scripts are loaded as soon as loadFrameScript() is called. If you've set allowDelayedLoad, the script is loaded into a new tab as soon as it is created.

Frame scripts are associated with a browser tab, not with a page. So once you load them, they stay loaded until the tab is closed, even if you reload the document or navigate.

If you want a frame script to do something whenever a new document is loaded, you can listen for the document-element-inserted notification.

Unloading frame scripts

Frame scripts are automatically unloaded when the tab hosting them is closed. There is currently no way to unload them once you have loaded them, other than closing the tab they were loaded into.

When your add-on is uninstalled or disabled, you should:

  • if you used allowDelayedLoad, cancel it by calling removeDelayedFrameScript, to ensure that the frame script is not loaded into any new tabs.
  • disable any frame scripts that are already loaded. There is no mechanism to unload frame scripts that are already loaded, so you need to send a message to your frame scripts telling them to disable themselves (for example, by undoing any changes they've made or removing any event listeners).

Note: you might think that there is a race condition here due to the asynchronous nature of the message passing:

  • your add-on is disabled for an upgrade
  • your add-on broadcasts "disable" to your frame scripts
  • your add-on is upgraded, and the new code loads new frame scripts
  • the new frame scripts receive the "disable" message, and stop working

In fact, the message manager guarantees that loadFrameScript and broadcastAsyncMessage are guaranteed to affect frame scripts in the order that they are called, so in this case "disable" will be received and consumed before the new frame scripts are loaded.

At the moment frame scripts are cached until the browser restarts: this problem is tracked as bug 1051238. This is especially a problem for restartless add-ons, because when a new version of the add-on is installed, the old frame scripts will not be unloaded. The workaround here is to randomize the frame script's URL, for example by appending "?" + Math.random() to it.

Document Tags and Contributors

 Contributors to this page: wiwang, wbamberg
 Last updated by: wiwang,