Frame script loading and lifetime 编辑
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 script just writes "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 that points to the frame script you want to load
- A boolean flag,
allowDelayedLoad
Note: if the message manager is a global frame message manager or a window message manager, loadFrameScript()
may load the script multiple times, once in each applicable frame.
chrome: URLs
Extension developers usually use a chrome://
URL to refer to the frame scripts.
To define the mapping between a chrome://
URL and a frame script packaged with an extension, use a "chrome.manifest" file to register a chrome URL:
// chrome.manifest
content my-e10s-extension chrome/content/
// chrome script
mm.loadFrameScript("chrome://my-e10s-extension/content/content.js", true);
allowDelayedLoad
If the message manager is a global frame message manager or a window message manager then:
If
allowDelayedLoad
istrue
, the frame script will be loaded into any new frame, which has opened after theloadFrameScript()
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 all new tabs opened afterwards.
- If
allowDelayedLoad
isfalse
, the script will only be loaded into frames which are open when the call was made.
If the message manager is a browser message manager, you should always pass true
here. Because a browser message manager only corresponds to a single browser tab, its loadFrameScript()
function will only ever load the frame script into that one tab. Passing allowDelayedLoad
is a way to ensure that the script is loaded correctly, in case the tab is not ready when making the call.
If you use allowDelayedLoad
, you can cancel it by using removeDelayedFrameScript
:
var mm = window.messageManager;
mm.removeDelayedFrameScript("chrome://my-e10s-extension/content/frame-script.js");
This means we will stop loading the script into new tabs. Note that this function will not remove any scripts which have been loaded earlier.
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 and not with a page. So once you load them, they will stay loaded until the tab is closed, even if you reload the document or navigate. If you want to limit a script to the lifetime of a page you can create a Sandbox instead, where the current content page is used as prototype.
If you want a frame script to do something when a new document is loaded, you need to listen for an appropriate DOM event, generally DOMWindowCreated
, DOMContentLoaded
, or load
.
Unloading frame scripts
Frame scripts are automatically unloaded when their hosting tab is closed. There is currently no way to unload them when loaded, other than closing the tab they were loaded into.
To listen for an event, when your frame script is unloaded (due to tab close for instance), you must set the third argument of addMessageListener
to true. For example, from 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
);
Then in your frame script, listen for the unload event of the message manager (which is the global this
), and sending a message. If you did not set the third argument to true in bootstrap.js
on Services.mm.addMessageListener
, sending this message during, and after, the unloading 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);
Note about unload during uninstallation/upgrade
When your add-on is uninstalled, or disabled, you should:
- Cancel it, If you have used
allowDelayedLoad
, by callingremoveDelayedFrameScript
; ensuring the frame script is not loaded into any new tabs. - Disable any frame scripts already loaded. There is no mechanism to unload frame scripts which are already loaded. 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.
There is a bug in non-e10s where this order 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 a problem especially 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 is to randomize the frame script's URL; for example, by appending "?" + Math.random()
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论