兩個瀏覽器窗口間通訊

兩個瀏覽器窗口間通訊

補充一下,這裏的通信指遵照同源策略狀況下。html


爲了吸引讀者的興趣,先把demo放到前面:
下面有幾個我本身寫的演示多頁面通信的demo, 爲了正常運行,請用最新的chrome瀏覽器打開。
demo的源碼地址https://github.com/xiangwenhu/page-communication/tree/master/docs前端


爲何會扯到這個話題,最初是源於聽 https://y.qq.com/ QQ音樂,git

  • 播放器處於單獨的一個頁面
  • 當你在另外的一個頁面搜索到你滿意的歌曲的時候,點擊播放或添加到播放隊列
  • 你會發現,播放器頁面作出了響應的響應

這裏我又聯想到了商城的購物車的場景,體驗確實有提高。
剛開始,我懷疑的是Web Socket做妖,結果經過分析網絡請求和看源碼,並無。 最後發現是localStore的storage事件做妖,哈哈。github


迴歸正題,其實在通常正常的知識儲備的狀況下,咱們會想到哪些方案呢?web

  1. WebSocket

    這個沒有太多解釋,WebSocket 是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。固然是有代價的,須要服務器來支持。
    js語言,如今比較成熟穩定固然是 socket.iows. 也還有輕量級的ClusterWS

你能夠在The WebSocket API (WebSockets)看到更多的關於Web Socket的信息。chrome

  1. 定時器 + 客戶端存儲

定時器:setTimeout/setInterval/requestAnimationFrame
客戶端存儲: cookie/localStorage/sessionStorage/indexDB/chrome的FileSystemsegmentfault

定時器沒啥好說的,關於客戶端存儲。瀏覽器

  • cookie: 每次會帶到服務端,而且能存的並不大,4kb?,記得不太清楚
  • localStorage/sessionStorage 應該是5MB, sessionStorage關閉瀏覽器就和你說拜拜。
  • indexDB 這玩意就強大了,不過讀取都是異步的,還能存 Blob文件,真的是很high。
  • chrome的FileSystem ,Filesystem & FileWriter API,主要是chrome和opera支持。這玩意就是文件系統。
  1. postMessage

    Cross-document messaging 這玩意的支持率98.9%。 好像還能發送文件,哈哈,強大。
    不過仔細一看 window.postMessage(),就註定了你首先得拿到window這個對象。 也註定他使用的限制, 兩個窗體必須創建起聯繫。 常見創建聯繫的方式:
  • window.open
  • window.opener
  • iframe

提到上面的window.open, open後你能得到被打開窗體的句柄,固然也能夠直接操做窗體了。服務器


到這裏,我以爲通常的前端人員能想到的比較正經的方案應該是上面三種啦。
固然,咱們接下來講說可能不是那麼常見的另外三種方式。websocket

  1. StorageEvent

    Page 1
localStorage.setItem('message',JSON.stringify({
    message: '消息',
    from: 'Page 1',
    date: Date.now()
}))

Page 2

window.addEventListener("storage", function(e) {
    console.log(e.key, e.newValue, e.oldValue)
});

如上, Page 1設置消息, Page 2註冊storage事件,就能監聽到數據的變化啦。

上面的e就是StorageEvent,有下面特有的屬性(都是隻讀):

  • key :表明屬性名發生變化.當被clear()方法清除以後全部屬性名變爲null
  • newValue:新添加進的值.當被clear()方法執行過或者鍵名已被刪除時值爲null
  • oldValue:原始值.而被clear()方法執行過,或在設置新值以前並無設置初始值時則返回null
  • storageArea:被操做的storage對象
  • url:key發生改變的對象所在文檔的URL地址
  1. Broadcast Channel

    這玩意主要就是給多窗口用的,Service Woker也可使用。 firefox,chrome, Opera均支持,有時候真的是很討厭Safari,瀏覽器支持75%左右。

使用起來也很簡單, 建立BroadcastChannel, 而後監聽事件。 只須要注意一點,渠道名稱一致就能夠。
Page 1

var channel = new BroadcastChannel("channel-BroadcastChannel");
    channel.postMessage('Hello, BroadcastChannel!')

Page 2

var channel = new BroadcastChannel("channel-BroadcastChannel");
    channel.addEventListener("message", function(ev) {
        console.log(ev.data)
    });
  1. SharedWorker

    這是Web Worker以後出來的共享的Worker,不通頁面能夠共享這個Worker。
    MDN這裏給了一個比較完整的例子simple-shared-worker

這裏來個插曲,Safari有幾個版本支持這個特性,後來又不支持啦,仍是你Safari,真是6。

雖然,SharedWorker自己的資源是共享的,可是要想達到多頁面的互相通信,那仍是要作一些手腳的。
先看看MDN給出的例子的ShareWoker自己的代碼:

onconnect = function(e) {
  var port = e.ports[0];

  port.onmessage = function(e) {
    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
    port.postMessage(workerResult);
  }

}

上面的代碼其實很簡單,port是關鍵,這個port就是和各個頁面通信的主宰者,既然SharedWorker資源是共享的,那好辦,把port存起來就是啦。
看一下,以下改造的代碼:
SharedWorker就成爲一個純粹的訂閱發佈者啦,哈哈。

var portList = [];

onconnect = function(e) {
  var port = e.ports[0];
  ensurePorts(port);
  port.onmessage = function(e) {
    var data = e.data;
    disptach(port, data);
  };
  port.start();
};

function ensurePorts(port) {
  if (portList.indexOf(port) < 0) {
    portList.push(port);
  }
}

function disptach(selfPort, data) {
  portList
    .filter(port => selfPort !== port)
    .forEach(port => port.postMessage(data));
}

Broadcast

MDN Web Docs - Broadcast Channel
BroadcastChannel | Can I Use
broadcast-channel
BroadcastChannel that works in New Browsers, Old Browsers, WebWorkers and NodeJ
--------

StorageEvent

StorageEvent


SharedWorker

SharedWorker
simple-shared-worker
SharedWorker | Can I Use
共享線程 SharedWorker
feature-shared-web-workers
------

其餘

兩個瀏覽器窗口間通訊總結

相關文章
相關標籤/搜索