昨天學習了 Channel messaging
在主頁面與 iframe
間的訊息傳遞,而今天就讓我們來看看 MessagePort
怎麼在 web worker 中發揮 Transferable object
的作用吧。
以下範例創建兩個 worker
,並且將 MessageChannel
中產生的兩個 port
分別轉移到這兩個 worker
,使他們之間可以互相通信。
index.mjs (主線程)
// 首先我們創建兩個 worker
const worker1 = new Worker('public/worker1.mjs');
const worker2 = new Worker('public/worker2.mjs');
// 接著將 MessagePorts 分別轉移到 worker 1 & 2
const channel = new MessageChannel();
worker1.postMessage('INIT', [channel.port1]);
worker2.postMessage('INIT', [channel.port2]);
worker1.mjs
let port1;
const init = (port) => {
// 初始化,接收 MessageChannel 的 port
port1 = port;
port1.onmessage = (e) => {
console.log('worker1 中的 port1 接收到的資料', e.data);
};
};
const sendMessage = (data) => {
// 之後從主線程發送的資料,會從 port1 傳到 port2
console.log('worker1 接收到的資料', data);
port1.postMessage(data); // 這裡將資料直接傳遞到 port2 (也就是 worker2)
};
self.onmessage = (e) => {
const port = e.ports[0];
switch (e.data) {
case 'INIT':
init(port);
break;
default:
sendMessage(e.data);
break;
}
};
worker2.mjs
let port2;
const init = (port) => {
// 初始化,接收 MessageChannel 的 port
port2 = port;
port2.onmessage = (e) => {
console.log('worker2 中的 port2 接收到的資料', e.data);
};
};
const sendMessage = (data) => {
// 之後從主線程發送的資料,會從 port2 傳到 port1
console.log('worker2 接收到的資料', data);
port2.postMessage(data); // 這裡將資料直接傳遞到 port1 (也就是 worker1)
};
self.onmessage = (e) => {
const port = e.ports[0];
switch (e.data) {
case 'INIT':
init(port);
break;
default:
sendMessage(e.data);
break;
}
};
以上範例,我們先將 MessageChannel
創建出來的 port1
及 port2
分別轉移到 worker1 跟 worker2 中使用,讓 worker 1 跟 worker 2 藉由 port 直接溝通,接著每次主線程發送訊息到 port1
或 port2
時,都會再轉送到另一個 port。
由這個小範例可以看到 MessageChannel
創建出來的 port
可以任意分給主線程或是 worker 線程,達到兩者之間的訊息溝通。