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。