本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com
面试官:跨页面通信的方式有哪些?
我:1. Web Worker;2. 本地存储;3.postMessage 等
面试官:本地存储都有哪些?
我:localStorage,sessionStorage,cookie。
面试官:sessionStorage 可以吗?
我:不可用吧?
面试官:localStorage 新开页面和当前页面 open 新页面都可以吗?
我:都可以吧?
....
有没有经历过面试用跨页面通信的问题不断深入的摧残你,但是你又不能给出明确回答的经历。巧了在下就经历过这个过程。为了痛定思痛决定从头开始将这些东西揉碎了吃到嘴里,然后面试的时候嚼碎了喂给面试官😈。
好了心碎的事情说完了下面直接上才艺。
同源页面间通信
什么是同源这个不过多解释了,大家可以自己了解一下[浏览器同源策略](developer.mozilla.org/zh-CN/docs/…[1])
1. localStorage
可以通过 localStroage.setItem() 在一个页面去写入一个值,然后在另一个页面中去获取。我们在 A 页面中添加一个按钮,用来设置 localStroage,然后在 B 页面添加一个定时器获取 A 页面设置的 localStroage,分别用直接链接访问和 A 页面跳转的方式打开 B 页面看是否能获取到 A 页面设置的 localStroage 的值。
A 页面设置
localStroage值
直接通过 A 页面调整 B 页面的结果
image.png
image.png
可以看到是可以访问到的。
通过链接直接访问 B 页面结果
image.png
结果同上是可以访问到的。
2. sessionStroage
操作方式同上面 localStroage,下面看一下结果
首先看 A 页面设置结果:
image.png
然后通过 A 页面跳转和直接访问 B 页面都得到结果是获取不到 A 页面设置的 sessionStroage:sessionStroage 不支持跨页面通信。
image.png
image.png
3.cookie
操作方式同上,在 A 页面设置了 testCookie=123 但是并不会在 cookie 中马上显示要刷新才能显示
image.png
通过两种方式打开 B 页面的结果
通过两种方式打开的 B 页面都可以获取到在 A 页面的 cookie,所以可以通过 Cookie 进行跨页面通信。
image.png
image.png
4. indexedDB 和 Web sql
如果页面有大量的数据需要交互,同时也需要做一些持久化的操作,前端的 sql 操作是一个比较好的选择,可以通过 indexedDB 创建一个关系型数据库来做数据存储,通过 sql 操作实现页面间的通信,更多的内容可以了解一下 IndexedDB[2] 的使用。
5.Broadcast Channel API
Broadcast Channel API 是 HTML5 提供的一种跨页面通信机制。它允许不同页面之间通过共享一个频道来进行通信。一个页面可以向频道发送消息,其他页面可以监听该频道以接收消息。
通过创建一个监听某个频道下的 BroadcastChannel[3] 对象,你可以接收发送给该频道的所有消息。一个有意思的点是,你不需要再维护需要通信的 iframe 或 worker 的索引。它们可以通过构造 BroadcastChannel[4] 来简单地 “订阅” 特定频道,并在它们之间进行全双工(双向)通信。
image.png
- 首先创建一个
BroadcastChannel对象:
var bc = new BroadcastChannel("test_tab");- 发送消息:
bc.postMessage("This is a test message.");- 接收消息:
bc.onmessage = function (ev) { console.log(ev);};- 与频道断开连接:
bc.close();通过上面方法,A 页面发送信息,在 B 页面就可以接收到 A 页面发送的消息。
A 页面代码:
export default function Success() { const setLocal = () => { const bc = new BroadcastChannel('test_tab') bc.postMessage('this is a test message') } return ( <Button onClick={setLocal}>设置消息</Button> );}B 页面代码:
const bc = new BroadcastChannel('test_tab')bc.onmessage = (ev) => { console.log('message', ev)}结果如下:
image.png
虽然 Broadcast Channel API 方便好用,但是在兼容性上不是特别好。
image.png
6. PostMessage API
PostMessage API 允许在不同浏览上下文(如不同窗口、iframe 或跨域页面)之间进行通信。页面可以使用 postMessage 方法发送消息,接收方页面可以通过监听 message 事件来接收和处理消息。
// A页面const targetWindow = window.open("目标页面的URL");// 发送消息const message = "Hello, target page!";const targetOrigin = "目标页面的URL";targetWindow.postMessage(message, targetOrigin);// 目标页面window.addEventListener("message", function(event) { // 确认消息来源 const allowedOrigin = "源页面的URL"; if (event.origin !== allowedOrigin) return; // 处理接收到的消息 const message = event.data; console.log("接收到的消息:", message);});在 A 页面中,我们使用 postMessage 方法向目标页面发送消息。首先,我们通过 window.open 方法打开目标页面的 URL,然后使用 postMessage 方法发送消息。在发送消息时,我们需要传递两个参数:要发送的消息内容和目标页面的 URL。
在目标页面中,我们使用 window.addEventListener 方法监听 message 事件。当消息被发送时,页面会触发 message 事件并传递一个 event 对象。我们可以通过 event.data 属性获取接收到的消息内容。在处理消息之前,我们可以验证消息的来源,以确保通信的安全性。
通过使用 PostMessage API,源页面和目标页面可以在跨域或不同窗口之间进行通信。这种方式可用于实现多种跨页面交互,如传递数据、同步状态等。请注意,为了确保安全性,应该验证消息的来源和目标,以防止恶意代码的注入。
7. Service Worker
Service Worker 是运行在浏览器后台的脚本,可以拦截和处理网络请求。虽然 Service Worker 主要用于离线缓存和推送通知等功能,但也可以用于实现跨页面通信。
在注册 Service Worker 时,我们可以监听 message 事件来接收和处理消息:
// 注册 Service Workernavigator.serviceWorker.register('service-worker.js');// 监听 message 事件navigator.serviceWorker.addEventListener('message', function(event) { // 处理接收到的消息 const message = event.data; console.log('接收到的消息:', message);});在源页面中,我们使用 postMessage 方法向 Service Worker 发送消息:
// A页面navigator.serviceWorker.controller.postMessage('Hello, Service Worker!');在 Service Worker 脚本中,我们可以监听 message 事件来接收和处理消息,并向所有客户端页面发送消息:
// B页面// 监听 message 事件self.addEventListener('message', function(event) { // 处理接收到的消息 const message = event.data; console.log('接收到的消息:', message); // 向所有客户端页面发送消息 self.clients.matchAll().then(function(clients) { clients.forEach(function(client) { client.postMessage('Hello, client page!'); }); });});在 A 页面中,使用 navigator.serviceWorker.controller.postMessage 方法向 Service Worker 发送消息。在 B 页面中,可以通过监听 message 事件来接收和处理消息,并使用 self.clients.matchAll 方法获取所有的客户端页面,并向每个页面发送消息。
使用 Service Worker 进行跨页面通信的好处是,Service Worker 可以在后台运行并独立于页面,这意味着即使没有页面打开,也可以进行跨页面通信。这对于实现离线通知、消息同步等功能非常有用。
请注意,Service Worker 只能与同源页面通信,因此源页面和 Service Worker 脚本必须在同一域下。并且由于 Service Worker 生命周期的特性,首次注册成功后,才能在后续页面加载中接收到消息。
8. web Worker
Web Worker 是一种运行在后台的 JavaScript 线程,可以用于执行长时间运行的任务而不会阻塞主线程。Web Worker 本身不能直接进行跨页面通信,但可以通过 MessageChannel API 进行跨页面通信
// A页面const sharedWorker = new SharedWorker('shared-worker.js');sharedWorker.port.onmessage = function(event) { // 处理接收到的消息 const message = event.data; console.log('接收到的消息:', message);};// 发送消息给 Shared WorkersharedWorker.port.postMessage('Hello, Shared Worker!');// B页面const sharedWorker = new SharedWorker('shared-worker.js');sharedWorker.port.onmessage = function(event) { // 处理接收到的消息 const message = event.data; console.log('接收到的消息:', message);};// shared-worker.js// 监听 connect 事件self.onconnect = function(event) { // 获取通信端口 const port = event.ports[0]; // 监听消息 port.onmessage = function(event) { // 处理接收到的消息 const message = event.data; console.log('接收到的消息:', message); // 向所有连接的源页面发送消息 port.postMessage('Hello, source pages!'); };};9. WebSocket
WebSocket 是一种在 Web 应用程序中实现双向通信的协议。它允许在客户端和服务器之间建立持久的连接,以便实时地发送数据。
可以通过 WebSocket 建立一个长连接通过后端服务器的中转进行页面间的通信。
非同源
通过链接跳转的方式,将需要用到的参数进行传递。
通过内嵌一个同源的 iframe 页面,先将参数传给 iframe 页面,然后让 iframe 页面进行上面的同源操作进行交互。
小结
通过上面的方法可以进行跨页面通信,我已经揉碎了吃到嘴里了,接下来就是嚼碎了吐给面试官,方便面试官快速消化😈。
作者:托儿所夜十三
链接:https://juejin.cn/post/7298644594857410614
来源:稀土掘金
往期回顾
如何使用 TypeScript 开发 React 函数式组件?
6 个你必须明白 Vue3 的 ref 和 reactive 问题
回复 “加群”,一起学习进步