Channel Messaging API
Channel Messaging API允許iframe和worker通過通道與主文檔線程進行通信,通過傳遞消息。
- [引言Channel Messaging API](#引言Channel Messaging API)
- iframe的示例
- [Service Worker的示例](#Service Worker的示例)
- 瀏覽器支援
引言Channel Messaging API
在同一個文檔中運行的兩個腳本,但處於不同的上下文中,Channel Messaging API允許它們通過通道進行通信。
此用例涉及以下通信方式:
- 文檔和iframe之間的通信
- 兩個iframe之間的通信
- 兩個文檔之間的通信
它是如何工作的
調用new MessageChannel()
來初始化消息通道。
1 | const channel = new MessageChannel() |
該通道具有2個屬性,稱為
- port1
- port2
這些屬性均為MessagePort對象。port1
是由創建通道的一方使用的端口,而port2
是通道接收器使用的端口(順帶一提,通道是雙向的,因此接收器也可以發送消息)。
在通道的每一端,您都可以在一個端口上進行侦聽,並將消息發送到另一個端口。
通過otherWindow.postMessage()
方法發送消息,其中otherWindow
是另一個瀏覽上下文。它接受一個消息,一個源和一個端口。
例如:
1 | const data = { name: 'Flavio' } |
消息可以是下列支援的值之一:
- 所有原始類型,但排除符號
- 數組
- 物件文本
- 字符串,日期,正則表達式對象
- Blob,File,FileList對象
- ArrayBuffer,ArrayBufferView對象
- FormData對象
- ImageData對象
- Map和Set對象
“源”是一個URI(例如https://example.org
)。您可以使用'*'
來允許不嚴格的檢查,或指定一個域,或者指定'/'
以設置同一域目標,而無需指定所屬域。
其他瀏覽上下文使用message
事件來聆聽消息:
1 | self.addEventListener('message', event => { |
self
在這種情況下與使用window
相同。
在事件處理程序內部,我們可以通過查看事件對象的data
屬性來訪問發送的數據:
1 | self.addEventListener('message', event => { |
我們可以通過使用MessagePort.postMessage
來回應:
1 | self.addEventListener('message', event => { |
通過在端口上調用close()
方法,可以關閉通道:
1 | self.addEventListener('message', event => { |
iframe的示例
以下是文檔和嵌入其中的iframe之間發生的通信示例。
主文檔定義一個iframe
和一個span
,我們將在其中打印從iframe
文檔發送的消息。一旦iframe
文檔加載完畢,我們就在我們創建的channel
上給它發送一個消息。
1 |
|
iframe頁面的源代碼更加簡單:
1 |
|
正如您所看到的,我們甚至不需要初始化一個channel,因為當從容器頁面接收到消息時,window.onmessage
處理程序會自動運行。
發送的事件由以下屬性組成:
data
:從其他窗口發送的對象origin
:發送消息的窗口的源URIsource
:發送消息的窗口對象
始終驗證消息發送者的來源。
e.ports[0]
是我們在iframe中引用port2
的方式,因為ports
是一個數組,並且該端口被添加到第一個元素。
在我的回答中翻译
Service Worker的示例
Service Worker是事件驅動的worker,其是與web頁面關聯的JavaScript文件。請查看Service Workers指南以了解更多有關它們的信息。
重要的是要知道Service Worker與主線程隔離,我們必須使用消息與它們進行通信。
以下是附加到主文檔的腳本如何處理發送消息給Service Worker:
1 | // `worker`是已實例化的Service Worker |
在Service Worker代碼中,我們為message
事件添加了一個事件監聽器:
1 | self.addEventListener('message', event => { |
它可以通過將消息發送到messageChannel.port2
來發送消息回來:
1 | self.addEventListener('message', event => { |
瀏覽器支援
Channel Messaging API當前得到了所有主要瀏覽器的支援,其中很多瀏覽器已經支援了許多年,因此即使是舊版本的瀏覽器也支援它。有關詳細信息,請參閱https://caniuse.com/#feat=channel-messaging。