您当前的位置:首页 > 计算机 > 软件应用 > 浏览器应用

浏览器多个标签页之间的通信

时间:12-14来源:作者:点击数:

prologue

之前在网上看到一个面试题:如何实现浏览器中多个标签页之间的通信。我目前想到的方法有三种:使用 websocket 协议、通过 localstorage、以及使用 html5 浏览器的新特性 SharedWorker。

websocket 这里先不介绍了,全双工 full-duplex 通信自然可以实现多个标签页之间的通信,相信网上通过 websocket 实现聊天室的教程也不少,我自己也用 socket.io 写了一个 在线聊天室。

接下来会介绍另外两个方法:监听 localstorage 和使用 SharedWorker。

localstorage

localstorage 是浏览器多个标签共用的存储空间,所以可以用来实现多标签之间的通信,session 是会话级的存储空间,每个标签页都是单独的。

直接在 window 对象上添加监听即可:

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

onstorage 以及 storage 事件,针对都是非当前页面对 localStorage 进行修改时才会触发,当前页面修改 localStorage 不会触发监听函数。然后就是在对原有的数据的值进行修改时才会触发,比如原本已经有一个key会a值为b的 localStorage,你再执行:localStorage.setItem('a', 'b') 代码,同样是不会触发监听函数的。

webworker

我们都知道 JavaScript 是单线程的,但是浏览器是拥有过个线程的比如:gui 渲染线程、JS 引擎线程、事件触发线程、异步 http 请求线程。

webworker 作为浏览器的一个新特性,可以提供一个额外的线程来执行一些js代码,并且不会影响到浏览器用户界面。

应用场景:比如页面中包含耗时较大的算法代码时,就会阻塞线程影响浏览器渲染等等。这时候就可把耗时代码,放到 webworker(另一个线程)中执行。

注意,这种多线程能力不是 JavaScript 语言原生具有的,而是浏览器宿主环境提供的。

普通的 webworker 直接使用 new Worker() 即可创建,这种 webworker 是当前页面专有的。然后还有种共享 worker(SharedWorker),这种是可以多个标签页、iframe共同使用的,接下来介绍如何使用SharedWorker实现标签页之间的通信。

SharedWorker

SharedWorker 可以被多个 window 共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号),首先新建一个 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 监听信息的事件,客户端(即使用 sharedWorker 的标签页)发送 message 时就会触发。注意 webworker 无法在本地使用,出于浏览器本身的安全机制,所以我这次的示例也是放在服务器上的,worker.js 和 index.html 在同一目录。

因为客户端和 webworker 端的通信不像 websocket 那样是全双工的,所以客户端发送数据和接收数据要分成两步来处理。示例中会有两个按钮,分别对应的向 sharedWorker 发送数据的请求以及获取数据的请求,但他们本质上都是相同的事件--发送消息。

webworker 端会进行判断,传递的数据为 get 时,就把变量 data 的值回传给客户端,其他情况,则把客户端传递过来的数据存储到 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的数据:', e.data)
      }, false)
      worker.port.start()
      window.worker = worker
    }
// 获取和发送消息都是调用postMessage方法,我这里约定的是传递'get'表示获取数据。
window.worker.port.postMessage('get')
window.worker.port.postMessage('发送信息给worker')

页面A发送数据给 worker,然后打开页面 B,调用 window.worker.port.postMessage('get'),即可收到页面 A 发送给 worker 的数据。

参考:developer.mozilla.org/zh-CN/docs/…

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐