框架脚本的加载与寿命

这篇翻译不完整。请帮忙从英语翻译这篇文章

加载框架脚本

要加载一个框架脚本,使用 loadFrameScript() 函数。

这行代码加载一个框架脚本到当前选中的标签页。该框架脚本只是将 "foo" 写入到命令行:

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

loadFrameScript() 有两个强制性参数:

  • 一个 URL 指向要加载的框架脚本。
  • 一个布尔变量,allowDelayedLoad

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

chrome: URL

扩展开发者通常会使用 chrome:// URL 来指向一个框架脚本。

要定义 chrome:// URL 的映射和将一个框架脚本打包到扩展中,使用 "chrome.manifest" 文件来 注册一个chrome URL

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

allowDelayedLoad

如果消息管理器是一个 全局框架消息管理器 或者一个 窗口消息管理器,那么:

  • 如果 allowDelayedLoadtrue,在 loadFrameScript() 调用后,框架脚本将加载到任何新的已打开的标签页。例如:

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

    这段脚本将加载到此窗口中目前已打开的所有标签页,以及未来进入的新打开的标签页。

  • 如果 allowDelayedLoad  为 false,那么脚本只会在执行调用时已打开的标签页中加载。

如果消息管理器是一个 浏览器消息管理器,你应该始终在这里传递 true。因为一个浏览器消息管理器永远只对应一个浏览器标签页,它的 loadFrameScript() 函数只加载框架脚本到一个标签页。因此传递 allowDelayedLoad 仅仅是一个方法来确保脚本被正确加载,在你的标签页在执行后还没有准备好时。

如果你使用 allowDelayedLoad,你可以使用 removeDelayedFrameScript 取消它:

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

这意味着我们将停止加载脚本到新的标签页。请注意,此函数不会移除已经加载的任何脚本。

框架脚本的寿命

框架脚本将在 loadFrameScript() 被调用后尽快加载。如果你设置了 allowDelayedLoad,脚本将加载到一个新的标签页,一旦其已被创建。

框架脚本与浏览器的标签页相关联,而不是与页面。因此一旦你加载它们,它们就会持续存在,直至标签页被关闭,因此即便你重新加载或者文档重新导航也不会丢失。

如果你想一个框架脚本在每次新文档被加载后执行操作,你需要监听一个适当的 DOM 事件,通常是 DOMWindowCreated, DOMContentLoaded,  或者 load

卸载框架脚本

框架脚本会在托管它们的标签页被关闭时自动卸载。目前还没有办法在已加载它们的标签页之中卸载它们,除了关闭标签页。

若要监听你的框架脚本被卸载的事件(例如由于标签页被关闭),你必须将 addMessageListener 的第三个参数设置为 true,例如下面的 bootstrap.js 的代码:

Services.mm.addMessageListener(
    'my-addon-id',
    {
        receiveMessage: function() {
            console.log('incoming message from frame script:', aMsg.data);
        }
    },
    true // must set this argument to true, otherwise sending message from framescript will not work during and after the unload event on the ContentMessageManager triggers
);

and then in your frame script listen for the unload event of the message manager (which is the global this), and then send a message. If you did not set third argument to true in bootstrap.js on Services.mm.addMessageListener, then this send message during and after unload event, will do nothing.

var gContentFrameMessageManager = this;

addEventListener('unload', function(aEvent) {
    if (aEvent.target == gContentFrameMessageManager) {
        sendAsyncMessage('my-addon-id', 'framescript-died'); // if you did not set third argument of `Services.mm.addMessageListener` to `true`, then this will fail to send a message
    }
}, false);

有关卸载/升级操作时的卸载

在你的附加组件被卸载或禁用时,你应该:

  • 如果使用了 allowDelayedLoad,调用 removeDelayedFrameScript 取消它,确保框架脚本不会加载到任何新的标签页。
  • 禁用已加载的任何框架脚本。没有任何机制来卸载已加载的框架脚本,因此你需要发送一个消息到你的框架脚本来告诉它们禁用自己(例如撤销所有已取得的更改,以及移除事件监听器)。

There is a bug in non-e10s where this oder is not true. In e10s framescripts work fine on updating. For non-e10s waiting for Bug 1202125 - framescripts are not backwards loaded in message order in non-e10s.

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.

文档标签和贡献者

 此页面的贡献者: yfdyh000
 最后编辑者: yfdyh000,