使用通道訊息
注意:此功能在 Web Workers 中可用。
該通道訊息 API允許在同一文件附加的兩個獨立指令碼(例如,兩個<iframe>元素、主文件和單個<iframe>,或透過SharedWorker的兩個文件)直接通訊,透過雙向通道(或管道)在每個端點有一個埠之間傳遞訊息。
在本文中,我們將探討這項技術的基礎知識。
用例
通道訊息主要適用於需要將來自其他網站的功能透過 iframe 嵌入到主介面的社交網站,例如遊戲、通訊錄或帶有個性化音樂選擇的音訊播放器。當它們作為獨立單元執行時,一切都還好,但當您想要主網站和<iframe>元素之間,或不同<iframe>元素之間進行互動時,就會出現困難。例如,如果您想從主網站向通訊錄新增聯絡人,將遊戲中的高分新增到主個人資料,或者從音訊播放器新增新的背景音樂選擇到遊戲中,該怎麼辦?由於 Web 使用的安全模型,使用傳統 Web 技術來實現這些功能並不容易。您需要考慮來源之間是否相互信任,以及訊息如何傳遞。
另一方面,訊息通道可以提供一個安全通道,允許您在不同的瀏覽上下文之間傳遞資料。
注意:有關更多資訊和想法,規格中“Web 上的物件能力模型基礎埠”部分是一篇有用的讀物。
簡單示例
為了幫助您入門,我們在 GitHub 上釋出了一些演示。首先,請檢視我們的通道訊息基本演示(也可以線上執行),它展示了一個頁面和嵌入的<iframe>之間非常簡單的單訊息傳輸。
其次,請檢視我們的多訊息演示(可以線上執行),它展示了一個稍微複雜的設定,可以在主頁面和 IFrame 之間傳送多條訊息。
在本文中,我們將重點介紹後一個示例,該示例看起來像

建立通道
在演示的主頁面中,我們有一個簡單的表單,其中包含一個文字輸入框,用於輸入要傳送到<iframe>的訊息。我們還有一個段落,稍後將用它來顯示將從<iframe>收到的確認訊息。
const input = document.getElementById("message-input");
const output = document.getElementById("message-output");
const button = document.querySelector("button");
const iframe = document.querySelector("iframe");
const channel = new MessageChannel();
const port1 = channel.port1;
// Wait for the iframe to load
iframe.addEventListener("load", onLoad);
function onLoad() {
// Listen for button clicks
button.addEventListener("click", onClick);
// Listen for messages on port1
port1.onmessage = onMessage;
// Transfer port2 to the iframe
iframe.contentWindow.postMessage("init", "*", [channel.port2]);
}
// Post a message on port1 when the button is clicked
function onClick(e) {
e.preventDefault();
port1.postMessage(input.value);
}
// Handle messages received on port1
function onMessage(e) {
output.innerHTML = e.data;
input.value = "";
}
我們首先透過使用MessageChannel()建構函式建立一個新的訊息通道。
當 IFrame 載入完成後,我們為我們的按鈕註冊一個onclick處理程式,併為MessageChannel.port1註冊一個onmessage處理程式。最後,我們使用window.postMessage方法將MessageChannel.port2傳輸到 IFrame。
讓我們更詳細地研究一下iframe.contentWindow.postMessage行的工作原理。它接受三個引數
- 要傳送的訊息。對於這個初始的埠傳輸,訊息可以是一個空字串,但在本例中它被設定為
'init'。 - 訊息要傳送到的源。
*表示“任何源”。 - 一個物件,其所有權被轉移到接收瀏覽上下文。在這種情況下,我們將
MessageChannel.port2傳輸到 IFrame,以便它可以使用它與主頁面進行通訊。
當我們的按鈕被點選時,我們阻止表單正常提交,然後透過MessageChannel將我們在文字輸入框中輸入的值傳送到 IFrame。
在 IFrame 中接收埠和訊息
在<iframe>元素中,我們有以下 JavaScript
const list = document.querySelector("ul");
let port2;
// Listen for the initial port transfer message
window.addEventListener("message", initPort);
// Setup the transferred port
function initPort(e) {
port2 = e.ports[0];
port2.onmessage = onMessage;
}
// Handle messages received on port2
function onMessage(e) {
const listItem = document.createElement("li");
listItem.textContent = e.data;
list.appendChild(listItem);
port2.postMessage(`Message received by IFrame: "${e.data}"`);
}
當透過window.postMessage方法從主頁面接收到初始訊息時,我們執行initPort函式。此函式儲存傳輸的埠並註冊一個onmessage處理程式,該處理程式將在每次透過我們的MessageChannel傳遞訊息時被呼叫。
當收到來自主頁面的訊息時,我們建立一個列表項並將其插入到無序列表中,將列表項的textContent設定為事件的data屬性(其中包含實際訊息)。
接下來,我們透過呼叫最初傳輸到 iframe 的MessageChannel.port2上的MessagePort.postMessage,將一條確認訊息透過訊息通道傳送回主頁面。
在主頁面中接收確認
回到主頁面,現在讓我們看一下onmessage處理程式函式。
// Handle messages received on port1
function onMessage(e) {
output.innerHTML = e.data;
input.value = "";
}
當從 IFrame 收到確認原始訊息已成功接收的訊息時,這會將確認輸出到段落,並清空文字輸入框,以便傳送下一條訊息。
規範
| 規範 |
|---|
| HTML # message-channels |
| HTML # message-ports |
瀏覽器相容性
api.MessageChannel
載入中…
api.MessagePort
載入中…