runtime.Port
Port 对象表示两个特定上下文之间连接的一端,可用于交换消息。
一方使用 connect() API 发起连接。这将返回一个 Port 对象。另一方使用 onConnect 监听器侦听连接尝试。它会收到一个相应的 Port 对象。
一旦双方都拥有 Port 对象,它们就可以使用 Port.postMessage() 和 Port.onMessage 交换消息。当它们完成时,任一端都可以使用 Port.disconnect() 断开连接,这将在另一端生成 Port.onDisconnect 事件,使另一端能够执行任何必需的清理工作。
Port 也可能响应各种事件断开连接。请参阅 生命周期。
您可以使用此模式在
- 扩展的不同部分之间进行通信(例如,在 内容脚本和 后台脚本之间)
- 在您的扩展和 用户计算机上运行的原生应用程序之间。
- 在您的扩展和其他扩展之间
您需要为不同类型的连接使用不同的连接 API,如下表所示。
| 连接类型 | 发起连接尝试 | 处理连接尝试 |
|---|---|---|
| 后台脚本到内容脚本 | tabs.connect() |
runtime.onConnect |
| 内容脚本到后台脚本 | runtime.connect() |
runtime.onConnect |
| 扩展到原生应用程序 | runtime.connectNative() |
不适用(请参阅 原生消息)。 |
| 扩展到扩展 | runtime.connect() |
runtime.onConnectExternal |
类型
此类型的值是对象。它们包含以下属性:
name-
string。端口的名称,由创建它的runtime.connect()或tabs.connect()调用定义。如果此端口连接到原生应用程序,则其名称是原生应用程序的名称。 disconnect-
function。断开端口连接。任一端在完成端口使用后都可以调用此函数。它将导致在另一端触发onDisconnect。如果您希望另一端维护与此端口相关的某些状态,可以在断开连接时进行清理,则此功能非常有用。如果此端口连接到原生应用程序,此函数将关闭原生应用程序。 error-
object。如果端口因错误而断开连接,则此字段将设置为一个具有message字符串属性的对象,为您提供有关错误的更多信息。请参阅onDisconnect。 onDisconnect-
object。它包含所有使用 WebExtension API 构建的扩展的事件通用的addListener()和removeListener()函数。当另一端调用Port.disconnect()时,将调用侦听器函数。每个端口只会触发一次此事件。侦听器函数将收到Port对象。如果端口因错误而断开连接,则Port参数将包含一个error属性,提供有关错误的更多信息。jsport.onDisconnect.addListener((p) => { if (p.error) { console.log(`Disconnected due to an error: ${p.error.message}`); } });请注意,在 Google Chrome 中不支持
port.error:而是使用runtime.lastError来获取错误消息。 onMessage-
object。它包含所有使用 WebExtension API 构建的扩展的事件通用的addListener()和removeListener()函数。当另一端向此端口发送消息时,将调用侦听器函数。侦听器将收到另一端发送的值。 postMessage-
function。向另一端发送消息。此函数接受一个参数,该参数是一个可序列化的值(请参阅 数据克隆算法),代表要发送的消息。该消息将传递给侦听端口onMessage事件的任何脚本,或者如果此端口连接到原生应用程序,则传递给原生应用程序。 sender可选-
runtime.MessageSender。包含有关消息发送者的信息。仅在传递给runtime.onConnect、runtime.onConnectExternal或runtime.onUserScriptConnect侦听器的端口上存在。
生命周期
Port 的生命周期在 Chrome 文档中有描述。
然而,Firefox 和 Chrome 之间有一个重要的区别,源于 runtime.connect 和 tabs.connect API 是广播频道。这意味着可能存在多个接收者,当其中一个具有 runtime.onConnect 调用的上下文关闭时,这会导致歧义。在 Chrome 中,只要有任何其他接收者,端口就会保持活动状态。在 Firefox 中,当任何一个上下文卸载时,端口就会关闭。换句话说,断开连接条件,
- 接收到该端口的所有框架(通过
runtime.onConnect)都已卸载。
在 Chrome 中成立,在 Firefox 中被替换为
- 接收到该端口的*任何*框架(通过
runtime.onConnect)已卸载。
(请参阅 bug 1465514)。
示例
从内容脚本连接
此内容脚本
- 连接到后台脚本,并将
Port存储在名为myPort的变量中。 - 侦听
myPort上的消息并将其记录下来。 - 当用户单击文档时,使用
myPort向后台脚本发送消息。
// content-script.js
let myPort = browser.runtime.connect({ name: "port-from-cs" });
myPort.postMessage({ greeting: "hello from content script" });
myPort.onMessage.addListener((m) => {
console.log("In content script, received message from background script: ");
console.log(m.greeting);
});
document.body.addEventListener("click", () => {
myPort.postMessage({ greeting: "they clicked the page!" });
});
相应的后台脚本
-
侦听来自内容脚本的连接尝试。
-
当收到连接尝试时
- 将端口存储在名为
portFromCS的变量中。 - 使用该端口向内容脚本发送消息。
- 开始侦听通过该端口接收的消息,并将其记录下来。
- 将端口存储在名为
-
当用户单击扩展的浏览器操作图标时,使用
portFromCS向内容脚本发送消息。
// background-script.js
let portFromCS;
function connected(p) {
portFromCS = p;
portFromCS.postMessage({ greeting: "hi there content script!" });
portFromCS.onMessage.addListener((m) => {
console.log("In background script, received message from content script");
console.log(m.greeting);
});
}
browser.runtime.onConnect.addListener(connected);
browser.browserAction.onClicked.addListener(() => {
portFromCS.postMessage({ greeting: "they clicked the button!" });
});
多个内容脚本
如果您有多个内容脚本同时通信,您可能需要将每个连接存储在数组中。
// background-script.js
let ports = [];
function connected(p) {
ports[p.sender.tab.id] = p;
// …
}
browser.runtime.onConnect.addListener(connected);
browser.browserAction.onClicked.addListener(() => {
ports.forEach((p) => {
p.postMessage({ greeting: "they clicked the button!" });
});
});
连接到原生应用程序
此示例连接到名为“ping_pong”的原生应用程序,并开始侦听来自它的消息。它还在用户单击浏览器操作图标时向原生应用程序发送消息。
/*
On startup, connect to the "ping_pong" app.
*/
let port = browser.runtime.connectNative("ping_pong");
/*
Listen for messages from the app.
*/
port.onMessage.addListener((response) => {
console.log(`Received: ${response}`);
});
/*
On a click on the browser action, send the app a message.
*/
browser.browserAction.onClicked.addListener(() => {
console.log("Sending: ping");
port.postMessage("ping");
});
浏览器兼容性
加载中…
注意:此 API 基于 Chromium 的 chrome.runtime API。本文档摘自 Chromium 代码中的 runtime.json。