这篇翻译不完整。请帮忙从英语翻译这篇文章。
Chrome 的代码与框架脚本的往来通信采用消息 API,它可以包含可 JSON 序列化的对象作为参数。
这个 API 大多是对称的,但有一个主要的例外:框架脚本可以发送同步或者异步消息到 chrome,但 chrome 只能发送异步消息到内容。这是一种有意的设计,是为了防止内容不响应而导致的 chrome 失去响应。
在绝对必要时,框架脚本可以通过被称为 跨进程对象包装器(也称 CPOWs)的东西到达 chrome,并且 chrome 可以使用这些包装器来获得到内容对象的同步访问。
内容到 chrome
框架脚本可以选择发送同步消息或者异步消息到 chrome 代码。
异步消息
要发送异步消息,内容脚本应使用 sendAsyncMessage()
函数:
// frame script sendAsyncMessage("[email protected]:my-e10s-extension-message");
sendAsyncMessage()
takes one mandatory parameter, which is the name of the message. All messages share the same namespace, so to avoid conflicts with other code, you'll need to ensure that the names you use are unique. If you're using the message manager in an add-on, a good way to do that is to prefix messages with your add-on's ID.
After the name, you can pass detailed data as a string or a JSON-serializable object, and after that you can pass any objects it wants to pass to content as CPOWs.
The example below sends a message named "my-e10s-extension-message", with a data
payload containing details
and tag
properties, and exposes the event.target
object as a CPOW:
// frame script addEventListener("click", function (event) { sendAsyncMessage("[email protected]:my-e10s-extension-message", { details : "they clicked", tag : event.target.tagName }, { target : event.target }); }, false);
要接收来自内容的消息,一个 chrome 脚本需要使用消息管理器的 addMessageListener()
API 添加消息监听器:
传递给监听器的消息是一个对象,包含下列属性:
name |
字符串,包含消息的名称。 |
sync |
布尔值,表示消息是否为同步发送,或者是异步发送。 |
data |
JSON 对象,作为传递给 sendAsyncMessage() 的第二个参数。 |
target |
这是 XUL 的 <browser> 元素,来自消息发送的位置。 |
objects |
An object whose properties are any CPOWs exposed by the sender as the third argument to sendAsyncMessage() |
在下面的例子中,监听器只是记录所有的消息细节;
// chrome script messageManager.addMessageListener("[email protected]:my-e10s-extension-message", listener); function listener(message) { console.log(message.name); console.log(message.sync); console.log(message.data); console.log(message.target); console.log(message.objects); }
So combining this message listener with the message above will give console output somewhat like this, when the user clicks a <div>
:
"[email protected]:my-e10s-extension-message" false Object { details: "they clicked", tag: "div" } <xul:browser anonid="initialBrowser" ... > { target: <div#searchContainer> }
If your code requires access to a window
(for example to run window.openDialog
), and your message listener is run from somewhere without access to a window
(e.g. an XPCOM component), you can access the window of the browser
that sent the message with message.target.ownerDocument.defaultView
.
同步消息
要发送一个同步消息,框架脚本应使用全局的 sendSyncMessage()
函数:
// frame script sendSyncMessage("[email protected]:my-e10s-extension-message");
在一个 chrome 脚本收到一个同步消息时,它应该从它的消息监听器返回一个值:
// chrome script messageManager.addMessageListener("[email protected]:my-e10s-extension-message", listener); function listener(message) { return "value from chrome"; }
This value is then presented to the frame script in the return value of sendSyncMessage()
. Because a single message can be received by more than one listener, the return value of sendSyncMessage()
is an array of all the values returned from every listener, even if it only contains a single value:
// frame script addEventListener("click", function (event) { var results = sendSyncMessage("[email protected]:my-e10s-extension-message", { details : "they clicked", tag : event.target.tagName }); content.console.log(results[0]); // "value from chrome" }, false);
Like arguments, return values from sendSyncMessage()
must be JSON-serializable, so chrome can't return functions.
removeMessageListener()
要停止监听来自内容的消息,使用消息管理器的 removeMessageListener()
方法:
// chrome script messageManager.removeMessageListener("[email protected]:my-e10s-extension-message", listener);
Chrome 到内容
要从 chrome 发送一个消息到内容,你需要知道你正在使用什么类型的消息管理器。如果它是一个浏览器消息管理器,你可以使用消息管理器的 sendAsyncMessage
方法:
// chrome script browser.messageManager.sendAsyncMessage("[email protected]:message-from-chrome");
如果你有一个窗口或者全局消息管理器,你需要使用 broadcastAsyncMessage
方法:
// chrome script window.messageManager.broadcastAsyncMessage("[email protected]:message-from-chrome");
These methods takes one mandatory parameter, which is the message name. All messages share the same namespace, so to avoid conflicts with other code, you'll need to ensure that the names you use are unique. If you're using the message manager in an add-on, a good way to do that is to prefix messages with your add-on's ID.
在消息名称后,你可以将详细的数据传递为一个字符串或者一个可 JSON 序列化的对象:
// chrome script messageManager.sendAsyncMessage("[email protected]:message-from-chrome", { details : "some more details" });
To receive a message from chrome, a frame script uses the global addMessageListener()
function. This takes two parameters: the name of the message and a listener function. The listener will be passed a message
object whose data
property is the message payload:
// frame script function handleMessageFromChrome(message) { var payload = message.data.details; // "some more details" } addMessageListener("[email protected]:message-from-chrome", handleMessageFromChrome);
message-manager-disconnect
If you're using a message manager to communicate with a script that may be running in a different process, you can listen for the message-manager-disconnect observer notification to know when the message manager has disconnected from the other end of the conversation, so you can stop sending it messages or expecting to receive messages.
For example, suppose we load a script into the current <browser>
on some event, and keep the browser message manager in an array, so we can send it messages:
var messageManagers = []; ... // on some event var browserMM = gBrowser.selectedBrowser.messageManager; browserMM.loadFrameScript("chrome://[email protected]/content/frame-script.js", false); messageManagers.push(browserMM); console.log(messageManagers.length);
We can listen for message-manager-disconnect
to update the array when the message managers disconnect (for example because the user closed the tab):
function myObserver() { } myObserver.prototype = { observe: function(subject, topic, data) { var index = messageManagers.indexOf(subject); if (index != -1) { console.log("one of our message managers disconnected"); mms.splice(index, 1); } }, register: function() { var observerService = Cc["@mozilla.org/observer-service;1"] .getService(Ci.nsIObserverService); observerService.addObserver(this, "message-manager-disconnect", false); console.log("listening"); }, unregister: function() { var observerService = Cc["@mozilla.org/observer-service;1"] .getService(Ci.nsIObserverService); observerService.removeObserver(this, "message-manager-disconnect"); } } var observer = new myObserver(); observer.register();