在今天以前所介紹的都是一般較常用到的 Dedicated worker
,Dedicated worker
只能被當下創建的線程使用,而 Shared worker 則是只要符合同源的網域下,任意不同的 window
, iframe
或甚至是其他的 worker
線程都可以使用它。
Shared worker
藉由 第 10 天介紹到的 MessagePort 達到不同線程之間的溝通,所以需要使用 port 對象傳遞訊息
// 主線程
const worker = new SharedWorker('worker.js');
worker.port.postMessage(1);
不同於 Dedicated worker
只需要使用 onmessage 接收訊息,Shared worker
需要在 worker
連接上的時候先呼叫 onconnect 方法,取得連接到 worker
的 port
後,再使用 port
去接收或送出訊息
另外使用 port.addEventListener
或是 port.onmessage
接收訊息時有個小地方需要注意, port.addEventListener
的寫法接收訊息,一定要呼叫 port.start(),才有辦法順利收到訊息,但使用 port.onmessage
方式的寫法,底層會自動呼叫 start()
,就不用特別寫出來
例如,以下兩段程式碼是等價的:
self.onconnect = (e) => {
const port = e.ports[0];
port.addEventListener('message', (e) => {
port.postMessage(e.data);
});
port.start();
};
self.onconnect = (e) => {
const port = e.ports[0];
port.onmessage = (e) => {
port.postMessage(e.data);
};
};
跟上面提到的一樣,當使用 addEventListener('message')
的寫法時,port
連線不會自動建立,需要呼叫 port.start()
才能正確收到訊息
worker.port.onmessage = (e) => {
console.log(e.data);
};
worker.port.addEventListener('message', (e) => {
console.log(e.data);
});
worker.port.start();
Dedicated worker
每次創建時都會是一個新的 worker
,只能被創建當下的線程所使用,但 Shared worker
不論被創建了多少次,所有頁面(tab) 都是共用同一個 worker
,以下表格統整 不同事件 所產生的 總 worker 數量
Dedicated worker
const worker = new Worker('/worker.js');
事件 | 結果 | 總共 worker 數量 |
---|---|---|
tab1 創建 worker | 產生 worker1 | 1 |
tab2 創建 worker | 產生 worker2 | 2 |
關閉 tab1 | 終止 worker1 | 1 |
關閉 tab2 | 終止 worker2 | 0 |
Shared worker
const worker = new SharedWorker('/shared-worker.js');
事件 | 結果 | 總共 worker 數量 |
---|---|---|
tab1 創建 shared worker | 產生 shared worker1 | 1 |
tab2 創建 shared worker | 產生 shared worker2 | 1 |
關閉 tab1 | 終止 shared worker1 | 1 |
關閉 tab2 | 終止 shared worker2 | 0 |
只要是同源的網域下都可以共用同一個 Shared worker
,因此 Shared worker
的生命週期也與 Dedicated worker
不同,不論 Shared worker
被創建了幾次,指向的都是同一個 Shared worker
SharedWorker
The secret of successfully using multi window WebGL Canvas
JavaScript Web Workers(三)共享Worker