面试官:你是如何实现浏览器多标签页之间通信的?

简介: 前言我们都知道浏览器是可以打开很多标签页的,如果每个标签页代表的是单独的一个网站,那么这些标签页之间肯定是不能通信的,如果能通信那估计我们都得凉凉。但是在很多情况下,浏览器中的很多标签页都属于某一个网站,而且这些标签页之间会使用一些相同的数据,这个时候我们就需要让这些标签页的数据都保持同步。比如很多博客网站,点击文章列表通常是打开一个新的标签页进入文章详情页,那么如果我们在文章详情页点赞、评论等操作,而文章列表页也使用了这些数据,这个时候我们需要保持两边的数据一致,衍生出来就是详情页改了数据,需要让列表页知道。总结来看:在某些情况下,实现多标签页之间通信是必要的!

1.localStorage实现通信


借助localStorage实现标签页之间通信在实际项目中使用的很多,因为它操作简单,易于理解。如果你还不是早localStorage的用法,那你一定得恶补了。


localStorage的特点:

  • 同域共享存储空间
  • 持久化将数据存储来浏览器
  • 提供事件监听localStorage变化


这里我们需要重点关注同域共享,如果多个标签页跨域了,那么数据将无法共享。


代码演示:

我们新建两个页面pageA和pageB,利用localStorage实现两个页面之间的通信。

示例代码:

pageA

// pageA.html
<body>
  <h1>pageA</h1>
</body>
<script>
  window.addEventListener("storage", (e) => {
    console.info("localStorage发生变化:", e)
  })
</script>

pageB

// pageB.html
<body>
  <h1>pageB</h1>
  <button id="btnB">添加数据到localStorage</button>
</body>
<script>
  let btnB = document.getElementById("btnB");
  let num = 0;
  btnB.addEventListener("click", () => {
    localStorage.setItem("num", num++)
  })
</script>


当我们点击pageB中的按钮时,会更改localStorage中的值。然后在pageA中的storage监听函数便会监听到localStorage发生变化。


pageA输出结果:74.png


可以看到在pageA中不仅可以拿到改变后的值,还可以拿到改变之前的值。通过这种方式,我们就可以将两个页面的数据进行同步了。


注意点:

  • pageA和pageB同源,即域名、端口、协议等都是相同的。
  • 使用storage事件监听localStorage变化


当然,如果你只是需要两个页面之间数据共享,那么可以不使用storage监听方法,直接通过localStorage.getItem()获取即可。


2.使用websocket


websocket是一种网络通讯协议。我们都知道在使用HTTP协议的时候,我们与服务端都是通过发请求的方式进行通讯的,而且这种通讯只能由客户端发起。websocket协议就弥补了这一缺点,它是一个全双工通信的协议,意味着客户端和服务端可以互相通信,享受平等关系。


最简单列子就是聊天室,我们在聊天室里面可以收消息,也可以发消息,只要我们与服务端通过websocket建立好了连接。


websocket特点:

  • 保持连接状态,HTTP协议是无状态连接,即请求完毕后就会关闭连接。
  • 全双工通信,客户端和服务端平等对待,可以互相通信。
  • 建立在TCP协议之上
  • 没有同源共享策略,即可实现跨域共享


通过以上websocket的特点,我们再来思考如何利用websocket实现多标签页通信?


其实实现原理页比较简单,假如我们pageA和pageB都与服务器建立了websocket连接,那么连个页面都可以实时接收服务端发来的消息,也可以实时向服务端发送消息。如果pageA更改了数据,那么向服务端发送一条消息或数据,服务端在将这条消息或数据发送给pageB即可,这样就简单实现了两个标签页之间的通信。


原理有点类似于”中介“,我们可以通过中介来进行沟通。


代码演示:

我们先来搭建一个简单的websocket服务器,用于pageA和pageB的连接,新建index.js文件。


初始化命令:

npm init -y
npm install --save ws
运行命令:node index.js


代码如下:

index.js

// index.js
let WebSocketServer = require("ws").Server;
let wss = new WebSocketServer({ port: 3000 });
// 创建保存所有已连接到服务器的客户端对象的数组
let clients = [];
// 为服务器添加connection事件监听,当有客户端连接到服务端时,立刻将客户端对象保存进数组中。
wss.on("connection", function (client) {
  console.log("一个客户端连接到服务器");
  if (clients.indexOf(client) === -1) {
    clients.push(client);
    // 接收客户端发送的消息
    client.on("message", function (msg) {
      console.log("收到消息:" + msg);
      // 将消息发送给非自己的客户端
      for (let key of clients) {
        if (key != client) {
          key.send(msg.toString());
        }
      }
    });
  }
});

pageA

// pageA
<script>
  // 创建一个websocket连接
  var ws = new WebSocket('ws://localhost:3000/');
  // WebSocket连接成功回调
  ws.onopen = function () {
    console.log("websocket连接成功")
  }
  // 这里接受服务器端发过来的消息
  ws.onmessage = function (e) {
    console.log("服务端发送的消息", e.data)
  }
</script>

pageB

<script>
  let btnB = document.getElementById("btnB");
  let num = 0;
  btnB.addEventListener("click", () => {
    ws.send(`客户端B发送的消息:${num++}`);
  })
  // 创建一个websocket连接
  var ws = new WebSocket('ws://localhost:3000/');
  // WebSocket连接成功回调
  ws.onopen = function () {
    console.log("websocket连接成功")
  }
</script>


当我们点击pageB中的按钮时,会通过websocket向服务端发送一条消息,服务端接收到这条消息之后,会将消息转发给pageA,这样pageA就得到了pageB传来的数据。


pageA输出结果:75.png

总体来说,原理很简单,只是需要了解websocket。通常情况下,我们不建议使用websocket来进行多标签页通信,因为这回增加服务器的负担。


3.SharedWorker


我们都知道JavaScript是单线程的,单线程有好处也有坏处。为了弥补JS单线程的坏处,webWorker随之被提出,它可以为JS创造多线程环境。如果还不了解webWorker的可以去官网初步了解一下。


sharedWorker就是webWorker中的一种,它可以由所有同源页面共享,利用这个特性,我们就可以使用它来进行多标签页之前的通信。


sharedWorker特点:

  • 跨域不共享,即多个标签页不能跨域
  • 使用port发送和接收消息
  • 如果url相同,且是同一个js,那么只会创建一个sharedWorker,多个页面共享这个sharedWorker


其实它和我们的webSocket实现多页面通讯的原理很类似,都是发送数据和接收数据这样的步骤,shardWorker就好比我们的webSocket服务器。


代码演示:

新建一个worker.js,编写代码。


代码如下:

// worker.js
const set = new Set()
onconnect = event => {
  const port = event.ports[0]
  set.add(port)
  // 接收信息
  port.onmessage = e => {
    // 广播信息
    set.forEach(p => {
      p.postMessage(e.data)
    })
  }
  // 发送信息
  port.postMessage("worker广播信息")
}

pageA

<script>
  const worker = new SharedWorker('./worker.js')
  worker.port.onmessage = e => {
    console.info("pageA收到消息", e.data)
  }
</script>

pageB

<script>
  const worker = new SharedWorker('./worker.js')
  let btnB = document.getElementById("btnB");
  let num = 0;
  btnB.addEventListener("click", () => {
    worker.port.postMessage(`客户端B发送的消息:${num++}`)
  })
</script>

上面的代码就是一个最简单的sharedWorker的应用,我们在pageA页面中初始化了sharedWorker,并且设置了接收消息的监听函数,当sharedWorker初始化完成之后,pageA便会接收到一条消息,如下图:


76.png

后我们在pageB中同样初始化了sharedWorker的示例,点击按钮广播消息,此时pageA便可以收到消息,是不是和websocket的原理很像啊。


pageA输出结果:

77.png


调试sharedWorker:

我们如何查看当前是运行的哪个sharedWorker呢?可以在浏览时输入:chrome://inspect。

找到sharedWorker选项,就可以看到运行的sharedWorker,如下图:78.png

兼容性查看:79.png


总结:

sharedWorker的原理和websocket有点类似,都是广播和接收的原理,但是它也有一些缺点,比如调试不太方便、兼容性不太好。所以使用的时候一定要结合实际情况使用。


4.使用cookie + setInterval


我们都知道cookie可以用来存储数据,而且它是同源共享的,借助它的这些特点,我们就可以利用cookie实现多页面的通讯。


cookie特点:

  • 跨域不共享
  • 具有存储空间限制
  • 请求会自动携带cookie

示例代码:

pageA

<script>
  setInterval(() => {
    //加入定时器,让函数每一秒就调用一次,实现页面刷新
    console.log("cookie",document.cookie)
  }, 1000);
</script>

pageB

<script>
  let btnB = document.getElementById("btnB");
  let num = 0;
  btnB.addEventListener("click", () => {
    document.cookie = `客户端B发送的消息:${num++}`
  })
</script>

输出结果:80.png


这种方式实现的原理非常简单,就是在需要接收消息的页面不断轮询去查询cookie,然后发送消息的页面将数据存储在cookie中,这样就实现了简单的数据共享。


总结


这里介绍了4中实现浏览器多标签页之前通讯的方法,它们优缺点也有优点,有的操作简单,有的已于理解等等,需要根据实际场景选择不一样的方法。

81.png

想要视频学习,可以移步B站:小猪课堂

相关文章
|
7月前
|
Web App开发 编解码 前端开发
面试题22:如何测试Web浏览器的兼容性?
面试题22:如何测试Web浏览器的兼容性?
181 3
|
2天前
|
人工智能 API 数据库
Browser Use:开源 AI 浏览器助手,自动完成网页交互任务,支持多标签页管理、视觉识别和内容提取等功能
Browser Use 是一款专为大语言模型设计的智能浏览器工具,支持多标签页管理、视觉识别、内容提取等功能,并能记录和重复执行特定动作,适用于多种应用场景。
78 0
Browser Use:开源 AI 浏览器助手,自动完成网页交互任务,支持多标签页管理、视觉识别和内容提取等功能
|
1月前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
1月前
|
Web App开发 搜索推荐 安全
|
1月前
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
66 1
|
2月前
|
存储 移动开发 API
如何实现浏览器内多个标签页之间的通信
在浏览器中,可通过三种方式实现多标签页通信:一是利用 `localStorage`,通过设置及监听数据变化实现信息传递;二是借助 `Broadcast Channel API`,在同一频道下双向传输消息;三是运用 `SharedWorker`,作为共享工件在各标签间架起沟通桥梁。每种方法依据实际需求选择使用。
|
2月前
|
算法 安全 前端开发
基于postMessage和BroadcastChannel实现浏览器跨Tab窗口通信的方法介绍
基于postMessage和BroadcastChannel实现浏览器跨Tab窗口通信的方法介绍
106 0
|
4月前
|
存储 JavaScript 容器
【Vue面试题十一】、Vue组件之间的通信方式都有哪些?
这篇文章介绍了Vue中组件间通信的8种方式,包括`props`传递、`$emit`事件触发、`ref`、`EventBus`、`$parent`或`$root`、`attrs`与`listeners`、`provide`与`inject`以及`Vuex`,以解决不同关系组件间的数据共享问题。
|
4月前
|
存储 JavaScript 前端开发
|
4月前
|
Web App开发 存储 缓存