BroadcastChannel 是 HTML 規範中用來讓多個線程互相溝通的方式,不像前兩天介紹的 MessageChannel
只能做到兩者之間的通訊,BroadcastChannel
以一對多廣播的方式傳送消息。
如下圖所示,BroadcastChannel
擔任中介者的角色將訊息傳遞給 window
, tab
或是 iframe
。
一開始需要為創建的 BroadcastChannel
取名,這裡的名稱是 worker_channel
,之後如果要與其他頻道進行通信的話,也要命名成同樣的名稱
const channel = new BroadcastChannel("worker_channel");
一樣用 postMessage
的方式將訊息傳遞出去,背後用到的也一樣是前幾天所提到的 structuredClone
算法先將訊息進行深複製。但 channel.postMessage 本身並沒有第二個 transfer 參數,所以數據的傳遞都是複製過的
channel.postMessage("This is a test message.");
當 BroadcastChannel
不會再使用到的時候,需要手動關閉它避免資源消耗
channel.close();
BroadcastChannel
的溝通對象之間只允許同源頁面,因此不需要像前兩天介紹到的 MessagePort
,接收訊息前需要先檢驗是否從可信任網域來的
接著讓我們看 BroadcastChannel
要怎麼與 web worker
做搭配,達到各種 worker
間的訊息溝通吧
範例中利用 BroadcastChannel
傳遞資料到 worker
中進行加減法運算,加法計算會將 [5, 3] 的值傳到 plus-worker 中,而減法計算會將 [5, 3] 的值傳到另一個 minus-worker,以下是程式碼的說明:
一開始時創建兩個 BroadcastChannel
,分別用做傳遞給 plus-worker 跟 minus-worker 的通訊管道
const plusWorkerChannel = new BroadcastChannel("plus_worker_channel");
const minusWorkerChannel = new BroadcastChannel("minus_worker_channel");
接著在按下計算按鈕後,取得輸入框的數值,並分別傳遞到兩個 worker
// 按下按鈕後,將數值分別傳到 worker 計算
document.querySelector('button').onclick = () => {
// 取得加法輸入框 (ex. [5, 3])
const plusValues = getValues('plus');
plusWorkerChannel.postMessage(plusValues);
// 取得減法輸入框數值 (ex. [5, 3])
const minusValues = getValues('minus');
minusWorkerChannel.postMessage(minusValues);
};
worker 接收到訊息後,分別進行計算,再將結果送回主頁面
plus-worker.js
const channel = new BroadcastChannel("plus_worker_channel");
channel.onmessage = (e) => {
console.log("plus-worker 接收到的資料", e.data);
const [value1, value2] = e.data;
channel.postMessage(value1 + value2);
};
minus-worker.js
const channel = new BroadcastChannel("minus_worker_channel");
channel.onmessage = (e) => {
console.log("minus-worker 接收到的資料", e.data);
const [value1, value2] = e.data;
channel.postMessage(value1 - value2);
};
最後主頁面從兩個 worker 收到的計算結果渲染到畫面上
plusWorkerChannel.onmessage = (e) => {
const pResult = document.querySelector('.plus-result');
pResult.textContent = e.data;
}
minusWorkerChannel.onmessage = (e) => {
const mResult = document.querySelector('.minus-result');
mResult.textContent = e.data;
}
利用 BroadcastChannel
可以做到一對多的雙向溝通,相比於 MessageChannel
來說使用上更靈活,而且只允許同源溝通的特性,也較為安全,不會接收到不同源來的惡意程式碼,但缺點是 channel.postMessage
沒有支援 transfer 的使用,代表只能完全複製訊息傳遞,或許不適合需要大量數據的場景。