SharedWorker?多頁面相互通信示例詳解
正文
SharedWorker
是一個新的Web Worker API
,它允許你在多個頁面之間共享一個Worker
。
SharedWorker
代表一種特定類型的Worker
,可以在多個瀏覽器上下文中運行,比如多個頁面或者多個iframe
。
什么是 SharedWorker
根據(jù)前幾篇的了解,大家應該對Worker
有了一定的了解,SharedWorker
是Worker
的一種,它允許你在多個頁面之間共享一個Worker
。
SharedWorker
對比于Service Worker
要簡單很多,同樣也是繼承與Worker
,但是它的生命周期是獨立于頁面的。
SharedWorker
和其他Worker
的相同,都是需要同源的,它是通過url
來區(qū)分是否是同一個SharedWorker
。
使用 SharedWorker
SharedWorker
的使用很簡單,只需要在創(chuàng)建Worker
的時候,需要傳入一個name
參數(shù),這個name
參數(shù)就是SharedWorker
的標識,相同的name
會共享同一個SharedWorker
。
const sharedWorker = new SharedWorker('worker.js', 'mySharedWorker');
默認情況下name
并不是必須的,這個時候相同的url
會共享同一個SharedWorker
。
const sharedWorker = new SharedWorker('worker.js');
創(chuàng)建SharedWorker
之后,我們就可以通過port
屬性來和SharedWorker
進行通信了。
sharedWorker.port.onmessage = (e) => { console.log(e.data); };
在主線程中,可以通過創(chuàng)建出來的worker
對象中的port
屬性來和SharedWorker
進行通信。
使用worker.port.onmessage
來監(jiān)聽SharedWorker
的消息。
在SharedWorker
中,可以通過self.onconnect
來監(jiān)聽SharedWorker
的連接。
在監(jiān)聽事件中會獲取到與SharedWorker
連接的port
,通過這個port
就可以和主線程進行通信了。
self.onconnect = (e) => { const port = e.ports[0]; port.postMessage('hello'); };
通信還是通過postMessage
來進行的。
通信
上面的通信只是一個簡單的示例,在主線程中創(chuàng)建的SharedWorker
,并使用port
來和SharedWorker
進行通信。
通常情況下,我們會使用onmessage
來監(jiān)聽SharedWorker
的消息,使用這種方式默認是打開狀態(tài),如果使用addEventListener
來監(jiān)聽SharedWorker
的消息,需要手動調(diào)用start
方法來開啟。
sharedWorker.port.addEventListener('message', (e) => { console.log(e.data); }); sharedWorker.port.start();
在主線程中,我們可以通過port
來實現(xiàn)和SharedWorker
的通信。
// 發(fā)送消息 sharedWorker.port.postMessage('hello'); // 監(jiān)聽消息 sharedWorker.port.onmessage = (e) => { console.log(e.data); }; // 或者 sharedWorker.port.addEventListener('message', (e) => { console.log(e.data); }); sharedWorker.port.start();
在SharedWorker
中使用方式也是一樣的,不同的是,我們需要通過self.onconnect
來監(jiān)聽SharedWorker
的連接。
self.onconnect = (e) => { const port = e.ports[0]; // 發(fā)送消息 port.postMessage('hello'); // 監(jiān)聽消息 port.onmessage = (e) => { console.log(e.data); }; // 或者 port.addEventListener('message', (e) => { console.log(e.data); }); port.start(); };
可以看到上面監(jiān)聽的時候,獲取port
是一個數(shù)組,這是因為SharedWorker
可以和多個頁面進行通信。
每個頁面都會有一個port
,通過這個port
和SharedWorker
進行通信。
通常情況下我們會記錄下所有的port
,然后在需要的時候進行通信。
const ports = []; self.onconnect = (e) => { const port = e.ports[0]; ports.push(port); port.onmessage = (e) => { console.log(e.data); }; }; // 發(fā)送消息 function sendMessage(message) { ports.forEach((port) => { port.postMessage(message); }); }
上面我們的案例中,我們只創(chuàng)建了一個SharedWorker
,所以只有一個port
,但是如果我們創(chuàng)建了多個SharedWorker
,那么就會有多個port
。
這里收到消息之后瀏覽器控制臺沒有任何打印信息,因為SharedWorker
的作用域中沒有window
對象,所以console
、alert
等方法都是無法使用的。
如果我們需要調(diào)試SharedWorker
,可以在瀏覽器地址欄中輸入chrome://inspect/#workers
,這樣就可以看到當前頁面中的SharedWorker
。
指定頁面通信
上面我們拿到了所有的port
,但是我們并不知道這個port
是哪個頁面的,所以我們需要在創(chuàng)建SharedWorker
的時候,指定每個頁面的標識。
但是很遺憾,SharedWorker
并沒有提供這樣的功能,所以我們需要自己實現(xiàn)。
這里我們可以使用雙數(shù)組來實現(xiàn),一個數(shù)組用來存儲頁面的標識,一個數(shù)組用來存儲port
。
const pages = []; const ports = []; self.onconnect = (e) => { const port = e.ports[0]; ports.push(port); // 獲取頁面標識 const page = Math.random().toString(36).substr(2); port.postMessage(page); pages.push(page); // 監(jiān)聽消息 port.onmessage = (e) => { const index = ports.indexOf(port); const page = pages[index]; // 這樣就可以知道是哪個頁面發(fā)來的消息了 console.log(page); }; };
有了上面的代碼,我們就可以知道是哪個頁面發(fā)來的消息了,并且也可以指定頁面發(fā)送消息。
實戰(zhàn)
上面我們已經(jīng)知道了如何使用SharedWorker
,那么我們就可以使用它來實現(xiàn)一個簡單的聊天室。
這里我們使用SharedWorker
來實現(xiàn)消息的轉(zhuǎn)發(fā),頁面之間的通信使用postMessage
。
- SharedWorker
const uuids = []; const ports = []; self.onconnect = (e) => { const port = e.ports[0]; ports.push(port); // 獲取頁面標識 const uuid = Math.random().toString(36).substr(2); uuids.push(uuid); port.postMessage({ type: 'connect', uuid: uuid }); // 監(jiān)聽消息 port.onmessage = (e) => { const index = ports.indexOf(port); const uuid = uuids[index]; // 群發(fā)消息 broadcast({ type: 'message', sender: uuid, message: e.data.message }); }; }; // 群發(fā)消息 const broadcast = (data) => { ports.forEach((port) => { port.postMessage(data); }); }
- index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .chat { width: 100%; height: 100%; display: flex; flex-direction: column; } #messages { height: 500px; width: 300px; overflow: auto; border: #3498db 1px solid; padding: 0 10px; } .chat__messages { flex: 1; overflow-y: auto; margin: 4px 0; } .sender { font-size: 12px; margin: 0; padding: 0; } .sender:after { content: ' :'; } .message { width: auto; max-width: 300px; background: #3498db; padding: 10px; border-radius: 10px; margin: 10px 0; font-size: 16px; color: #fff; } </style> </head> <body> <div class="chat"> <div id="messages"> </div> <div class="chat__input"> <input type="text" id="message"> <button id="send">發(fā)送</button> </div> </div> <script> let uuid = '' const sharedWorker = new SharedWorker('sharedWorker.js'); sharedWorker.port.onmessage = (e) => { if (e.data.type === 'connect') { uuid = e.data.uuid; alert('連接成功') return; } const messageDom = ` <div class="chat__messages"> <p class="sender" ${uuid === e.data.sender ? 'style="color: #165DFF"' : ""}>${e.data.sender}</p> <p class="message">${e.data.message}</p> </div> ` document.getElementById('messages').insertAdjacentHTML('beforeend', messageDom); // 滾動到底部 document.getElementById('messages').scrollTop = document.getElementById('messages').scrollHeight; }; document.getElementById('send').addEventListener('click', () => { const message = document.getElementById('message').value; if (!message) { alert('請輸入內(nèi)容') return; } const data = { type: 'message', message: message, } sharedWorker.port.postMessage(data); document.getElementById('message').value = ''; }); </script> </body> </html>
上面的代碼我們實現(xiàn)了一個簡單的聊天室,我們可以在多個頁面打開聊天室,然后在其中一個頁面發(fā)送消息,其他頁面都會收到消息。
上面的代碼中還有一個uuid
,=還可以基于這么來實現(xiàn)私聊,比如我們可以在頁面中添加一個select
,然后選擇一個用戶,然后在發(fā)送消息的時候,將uuid
傳遞過去,然后在SharedWorker
中判斷,如果是私聊,就只發(fā)送給指定的用戶。
這一塊就留給感興趣的同學自己實現(xiàn)了。
SharedWorker 的關(guān)閉
上面我們實現(xiàn)了一個簡單的聊天室,但是我們發(fā)現(xiàn),當我們關(guān)閉頁面的時候,SharedWorker
并沒有關(guān)閉,這是因為SharedWorker
是一個長連接,當我們關(guān)閉頁面的時候,SharedWorker
并沒有關(guān)閉,所以我們需要在頁面關(guān)閉的時候,手動關(guān)閉SharedWorker
。
// 關(guān)閉頁面的時候,關(guān)閉 SharedWorker window.addEventListener('beforeunload', () => { sharedWorker.port.postMessage({ type: 'close', uuid: uuid }); }); // SharedWorker.js /** 省略其他代碼 **/ onconnect = (e) => { const port = e.ports[0]; port.onmessage = (e) => { if (e.data.type === 'close') { const index = ports.indexOf(port); ports.splice(index, 1); return; } }; };
上面的代碼中,我們在頁面關(guān)閉的時候,發(fā)送一個close
的消息,然后在SharedWorker
中,將port
從ports
中移除,這樣就可以關(guān)閉SharedWorker
了。
SharedWorker 的生命周期
SharedWorker
的生命周期沒有那么復雜,不像ServiceWorker
有那么多的過程,它只有一條規(guī)則,就是當所有創(chuàng)建SharedWorker
的頁面關(guān)閉之后,那么SharedWorker
的生命就走到了盡頭,否則它就會一直常駐。
SharedWorker 還可以做什么?
聊天室只是一個小玩具,我們還可以做很多事情,我們最常見的就是跨頁面登錄,例如GitHub
,我們在一個頁面登錄,然后在其他頁面就可以獲取到登錄信息,這就是SharedWorker
的一個應用場景。
還有一個應用場景就是,我們可以在一個頁面中,監(jiān)聽一個WebSocket
,然后在其他頁面中,發(fā)送消息,這樣就可以實現(xiàn)跨頁面的WebSocket
。
其實任何跨頁面的通信,都可以使用SharedWorker
來實現(xiàn),但是SharedWorker
的缺點也很明顯,就是不支持IE
,所以如果你的項目需要兼容IE
,那么就不要使用SharedWorker
了。
優(yōu)點很明確,就是可以跨頁面通信,缺點也很明顯,就是瀏覽器兼容確實有點捉急。
總結(jié)
本文主要介紹了SharedWorker
的基本使用,并使用SharedWorker
實現(xiàn)了一個簡單的聊天室。
SharedWorker
的使用還是比較簡單的,不同于Worker
那么單純,SharedWorker
是一個長連接,所以我們可以在多個頁面中,共享一個SharedWorker
,這樣就可以實現(xiàn)跨頁面通信了。
不同于ServiceWorker
有那么多的限制,SharedWorker
除了兼容性其實功能非常強大,且在實際項目中的應用場景也更加廣泛。
以上就是SharedWorker 多頁面相互通信示例詳解的詳細內(nèi)容,更多關(guān)于SharedWorker 多個頁面通信的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Layui Table js 模擬選中checkbox的例子
今天小編就為大家分享一篇Layui Table js 模擬選中checkbox的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09JavaScript判斷頁面加載完之后再執(zhí)行預定函數(shù)的技巧
這篇文章主要介紹了JavaScript判斷頁面加載完之后再執(zhí)行預定函數(shù)的技巧,原理還是利用監(jiān)聽器監(jiān)聽元素事件、被觸發(fā)則執(zhí)行函數(shù),需要的朋友可以參考下2016-05-05微信小程序?qū)崿F(xiàn)跳轉(zhuǎn)詳情頁面
這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)跳轉(zhuǎn)詳情頁面,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-06-06原生JavaScript實現(xiàn)Tooltip浮動提示框特效
這篇文章主要為大家詳細介紹了原生JavaScript設(shè)計和實現(xiàn)Tooltip浮動提示框特效,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03JS向上取整、向下取整、四舍五入、取絕對值、取較大較小值及隨機數(shù)代碼示例
在Js中對數(shù)值進行操作的場景有,向上取整、向下取整、四舍五入、固定精度、固定長度、取整,這篇文章主要給大家介紹了關(guān)于JS向上取整、向下取整、四舍五入、取絕對值、取較大較小值及隨機數(shù)的相關(guān)資料,需要的朋友可以參考下2024-04-04