瀏覽器多個標簽頁之間的通信

一:websocket通訊

全雙工(full-duplex)通信自然可以實現(xiàn)多個標簽頁之間的通信

WebSocket是HTML5新增的協(xié)議,它的目的是在瀏覽器和服務器之間建立一個不受限的雙向通信的通道,比如說,服務器可以在任意時刻發(fā)送消息給瀏覽器。為什么傳統(tǒng)的HTTP協(xié)議不能做到WebSocket實現(xiàn)的功能?這是因為HTTP協(xié)議是一個請求-響應協(xié)議,請求必須先由瀏覽器發(fā)給服務器,服務器才能響應這個請求,再把數(shù)據(jù)發(fā)送給瀏覽器。

也有人說,HTTP協(xié)議其實也能實現(xiàn)啊,比如用輪詢或者Comet。這個機制的缺點一是實時性不夠,二是頻繁的請求會給服務器帶來極大的壓力。

Comet本質上也是輪詢,但是在沒有消息的情況下,服務器先拖一段時間,等到有消息了再回復。這個機制暫時地解決了實時性問題,但是它帶來了新的問題:以多線程模式運行的服務器會讓大部分線程大部分時間都處于掛起狀態(tài),極大地浪費服務器資源。另外,一個HTTP連接在長時間沒有數(shù)據(jù)傳輸?shù)那闆r下,鏈路上的任何一個網(wǎng)關都可能關閉這個連接,而網(wǎng)關是我們不可控的,這就要求Comet連接必須定期發(fā)一些ping數(shù)據(jù)表示連接“正常工作”。

WebSocket并不是全新的協(xié)議,而是利用了HTTP協(xié)議來建立連接。為什么WebSocket連接可以實現(xiàn)全雙工通信而HTTP連接不行呢?實際上HTTP協(xié)議是建立在TCP協(xié)議之上的,TCP協(xié)議本身就實現(xiàn)了全雙工通信,但是HTTP協(xié)議的請求-應答機制限制了全雙工通信。WebSocket連接建立以后,其實只是簡單規(guī)定了一下:接下來,咱們通信就不使用HTTP協(xié)議了,直接互相發(fā)數(shù)據(jù)吧。安全的WebSocket連接機制和HTTPS類似。首先,瀏覽器用wss://xxx創(chuàng)建WebSocket連接時,會先通過HTTPS創(chuàng)建安全的連接,然后,該HTTPS連接升級為WebSocket連接,底層通信走的仍然是安全的SSL/TLS協(xié)議。

WebSocket連接必須由瀏覽器發(fā)起,特點:

(1)建立在 TCP 協(xié)議之上,服務器端的實現(xiàn)比較容易。

(2)與 HTTP 協(xié)議有著良好的兼容性。默認端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。

(3)數(shù)據(jù)格式比較輕量,性能開銷小,通信高效。

(4)可以發(fā)送文本,也可以發(fā)送二進制數(shù)據(jù)。

(5)沒有同源限制,客戶端可以與任意服務器通信。

(6)協(xié)議標識符是ws(如果加密,則為wss),服務器網(wǎng)址就是 URL。

二:定時器setInterval+cookie

在頁面A設置一個使用?setInterval?定時器不斷刷新,檢查?Cookies?的值是否發(fā)生變化,如果變化就進行刷新的操作。

由于?Cookies?是在同域可讀的,所以在頁面 B 審核的時候改變?Cookies?的值,頁面 A 自然是可以拿到的。

這樣做確實可以實現(xiàn)我想要的功能,但是這樣的方法相當浪費資源。雖然在這個性能過盛的時代,浪費不浪費也感覺不出來,但是這種實現(xiàn)方案,確實不夠優(yōu)雅。

三:使用localstorage

localstorage是瀏覽器多個標簽共用的存儲空間,所以可以用來實現(xiàn)多標簽之間的通信(ps:session是會話級的存儲空間,每個標簽頁都是單獨的)。

直接在window對象上添加監(jiān)聽即可:

window.onstorage = (e) => {console.log(e)}// 或者這樣window.addEventListener('storage', (e) => console.log(e))

onstorage以及storage事件,針對都是非當前頁面對localStorage進行修改時才會觸發(fā),當前頁面修改localStorage不會觸發(fā)監(jiān)聽函數(shù)。然后就是在對原有的數(shù)據(jù)的值進行修改時才會觸發(fā),比如原本已經有一個key會a值為b的localStorage,你再執(zhí)行:localStorage.setItem('a', 'b')代碼,同樣是不會觸發(fā)監(jiān)聽函數(shù)的。

四:html5瀏覽器的新特性SharedWorker

普通的webworker直接使用new Worker()即可創(chuàng)建,這種webworker是當前頁面專有的。然后還有種共享worker(SharedWorker),這種是可以多個標簽頁、iframe共同使用的。

SharedWorker可以被多個window共同使用,但必須保證這些標簽頁都是同源的(相同的協(xié)議,主機和端口號)

首先新建一個js文件worker.js,具體代碼如下:

// sharedWorker所要用到的js文件,不必打包到項目中,直接放到服務器即可let data = ''onconnect = function (e) {? let port = e.ports[0]? port.onmessage = function (e) {? ? if (e.data === 'get') {? ? ? port.postMessage(data)? ? } else {? ? ? data = e.data? ? }? }}

webworker端(暫且這樣稱呼)的代碼就如上,只需注冊一個onmessage監(jiān)聽信息的事件,客戶端(即使用sharedWorker的標簽頁)發(fā)送message時就會觸發(fā)。

注意webworker無法在本地使用,出于瀏覽器本身的安全機制,所以我這次的示例也是放在服務器上的,worker.js和index.html在同一目錄。

因為客戶端和webworker端的通信不像websocket那樣是全雙工的,所以客戶端發(fā)送數(shù)據(jù)和接收數(shù)據(jù)要分成兩步來處理。示例中會有兩個按鈕,分別對應的向sharedWorker發(fā)送數(shù)據(jù)的請求以及獲取數(shù)據(jù)的請求,但他們本質上都是相同的事件--發(fā)送消息。

webworker端會進行判斷,傳遞的數(shù)據(jù)為'get'時,就把變量data的值回傳給客戶端,其他情況,則把客戶端傳遞過來的數(shù)據(jù)存儲到data變量中。下面是客戶端的代碼:

// 這段代碼是必須的,打開頁面后注冊SharedWorker,顯示指定worker.port.start()方法建立與worker間的連接

? ? if (typeof Worker === "undefined") {

? ? ? alert('當前瀏覽器不支持webworker')

? ? } else {

? ? ? let worker = new SharedWorker('worker.js')

? ? ? worker.port.addEventListener('message', (e) => {

? ? ? ? console.log('來自worker的數(shù)據(jù):', e.data)

? ? ? }, false)

? ? ? worker.port.start()

? ? ? window.worker = worker

? ? }

// 獲取和發(fā)送消息都是調用postMessage方法,我這里約定的是傳遞'get'表示獲取數(shù)據(jù)。

window.worker.port.postMessage('get')

window.worker.port.postMessage('發(fā)送信息給worker')

頁面A發(fā)送數(shù)據(jù)給worker,然后打開頁面B,調用window.worker.port.postMessage('get'),即可收到頁面A發(fā)送給worker的數(shù)據(jù)。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容