runtime.Port

A Port object represents one end of a connection between two specific contexts, which can be used to exchange messages.

One side initiates the connection, using a connect() API. This returns a Port object. The other side listens for connection attempts using an onConnect listener. This is passed a corresponding Port object.

Once both sides have Port objects, they can exchange messages using Port.postMessage() and Port.onMessage. When they are finished, either end can disconnect using Port.disconnect(), which will generate a Port.onDisconnect event at the other end, enabling the other end to do any cleanup required.

A Port can also become disconnected in response to various events. See Lifecycle.

You can use this pattern to communicate between

You need to use different connection APIs for different sorts of connections, as detailed in the table below.

连接类型 发起连接尝试 处理连接尝试
后台脚本到内容脚本 tabs.connect() runtime.onConnect
内容脚本到后台脚本 runtime.connect() runtime.onConnect
扩展到原生应用程序 runtime.connectNative() 不适用(请参阅 原生消息传递)。
扩展到扩展 runtime.connect() runtime.onConnectExternal

类型

Values of this type are objects. They contain the following properties

name

string. The port's name, defined in the runtime.connect() or tabs.connect() call that created it. If this port is connected to a native application, its name is the name of the native application.

disconnect

function. Disconnects a port. Either end can call this when they have finished with the port. It will cause onDisconnect to be fired at the other end. This is useful if the other end is maintaining some state relating to this port, which can be cleaned up on disconnect. If this port is connected to a native application, this function will close the native application.

error

object. If the port was disconnected due to an error, this will be set to an object with a string property message, giving you more information about the error. See onDisconnect.

onDisconnect

object. This contains the addListener() and removeListener() functions common to all events for extensions built using WebExtension APIs. Listener functions will be called when the other end has called Port.disconnect(). This event will only be fired once for each port. The listener function will be passed the Port object. If the port was disconnected due to an error, then the Port argument will contain an error property giving more information about the error

js
port.onDisconnect.addListener((p) => {
  if (p.error) {
    console.log(`Disconnected due to an error: ${p.error.message}`);
  }
});

Note that in Google Chrome port.error is not supported: instead, use runtime.lastError to get the error message.

onMessage

object. This contains the addListener() and removeListener() functions common to all events for extensions built using WebExtension APIs. Listener functions will be called when the other end has sent this port a message. The listener will be passed the value that the other end sent.

postMessage

function. Send a message to the other end. This takes one argument, which is a serializable value (see Data cloning algorithm) representing the message to send. It will be delivered to any script listening to the port's onMessage event, or to the native application if this port is connected to a native application.

sender 可选

runtime.MessageSender. Contains information about the sender of the message. This property will only be present on ports passed to onConnect/onConnectExternal listeners.

生命周期

The lifecycle of a Port is described in the Chrome docs.

There is, however, one important difference between Firefox and Chrome, stemming from the fact that the runtime.connect and tabs.connect APIs are broadcast channels. This means that there may be potentially more than one recipient, and this results in ambiguity when one of the contexts with a runtime.onConnect call is closed. In Chrome, a port stays active as long as there is any other recipient. In Firefox, the port closes when any of the contexts unloads. In other words, the disconnection condition,

  • All frames that received the port (via runtime.onConnect) have unloaded.

which holds in Chrome, is replaced by

  • Any frame that received the port (via runtime.onConnect) has unloaded.

in Firefox (see bug 1465514).

浏览器兼容性

BCD 表格仅在浏览器中加载

示例

从内容脚本连接

此内容脚本

  • 连接到后台脚本并存储Port到名为myPort的变量中。
  • myPort上监听消息并记录它们。
  • 当用户点击文档时,使用myPort向后台脚本发送消息。
js
// 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向内容脚本发送消息。
js
// 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!" });
});

多个内容脚本

如果您有多个内容脚本同时通信,您可能希望将每个连接存储在一个数组中。

js
// 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”并开始监听来自它的消息。它还会在用户点击浏览器操作图标时向原生应用程序发送消息。

js
/*
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