一起养成写作习惯!这是我参与「日新计划 4 月更文挑战」的第1天,点击查看活动详情。

背景

用户在实际的操作场景中会打开多个 Tab 页面A、B、C、D、E…。当用户在接口卡 E Tab 页退出登录,并且登录到新的账号,然后用户切换到非 E 的 Tab 时,发现登录信息没有刷新, 并且由于登录信息没有刷新,会出现操作异常。这个问题简单来说就是多个 Tab 信息没有同步。问题的关键在于一个 Tab 退出重新登录,需要通接口测试知到其他的 Tab 刷新到最新的信息。本质问题就前端工程师解决前端跨页接口自动化面通信

本篇文章就是对前端跨页面通信的解决方案做了浏览器数据如何恢复一个了解。

onstorage

WindowEventHandlers.onstora接口和抽象类的区别ge 属性包含一个在 storage 事件触发时运行的事件处理程序。当更改存储时会触发事件处理程序。

语法

window.onstorage=function(){...};

window.onstorage=function(e){
console.log(`The${e.key}keyhasbeenchangedfrom${e.oldValue}to${e.newValue}.`);
};
<divid="app"></div>
<buttonid="tab">新开Tab</button>
<buttonid="l-btn">触发LocalStorage更新</button>
<buttonid="s-btn">触发SessionStorage更新</button>
<script>
window.onstorage=function(e){
console.log(`The${e.key}keyhasbeenchangedfrom${e.oldValue}to${e.newValue}.`);
};
document.getElementById('tab').onclick=function(){
window.open('xxx');
}
document.getElementById('l-btn').onclick=function(){
localStorage.setItem('storage1',Date.now())
}
document.getElementById('s-btn').onclick=function(){
sessionStorage.setItem('storage1',Date.now())
}
</script>

面试装X:我知道的前端跨页面通信

面试装X:我知道的前端跨页面通信

Tips

  1. 该事件不在导致数据变化的当前页面触发(如果浏览器同时打开一个域名下面的接口crc错误计数多个页面,当其中的一个页面改变 数据时,其他所有页面的 storage 事件会被触发,而原始页面并不触发 storage 事件)。
  2. sessionStorage(❎)不能触发 storage 事件 , locaHTTPSlStorage(✅)可以。
  3. 如果修改的值未发生改变,将不会触发 onstorage 事件。
  4. 优点:浏览器支持效果好、API直观、操接口作简单。缺点浏览器:部分浏览器隐身模式下,无法设置 localStorage。如safari,这样也就导致 onstrage 事件无法使用。

除开少数浏览器数据如何恢复情况,lohtml网页制作calStorage的兼容性不错,就当前国内浏览器历史记录设置的情况,已经基本没有问题了。localStorage 的原理很简单,浏览器数据如何恢复浏览HTML器为每个域名划出https认证一块本地存储空间,用户网页浏览器怎么打开网站可以通过 localSto前端面试题rage 命名空间进行读写。

面试装X:我知道的前端跨页面通信

BroadCahttps域名st Channel

Broadcahtml文件怎么打开stChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅html是什么意思它。它允许同源的不同浏览器窗口,Tab页,frame或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。

说到 BroadCa浏览器的历史记录在哪st Channel 不得不说一下 postMessage,他们二者的最大区别就在于 postMhtml5essage 更像是点对点的通信,而 BroadCast Channel 是广播的方式,点到面。

语法

//创建
constbroadcastChannel=newBroadcastChannel('channelName');
//监听消息
broadcastChannel.onmessage=function(e){
console.log('监听消息:',e.data);
};
//发送消息
broadcastChannel.postMessage('测试:传送消息');
//关闭
broadcastChannel.close();
<divid="app"></div>
<buttonid="tab">新开Tab</button>
<buttonid="l-btn">发送消息</button>
<buttonid="s-btn">关闭</button>
<script>
//创建
constbroadcastChannel=newBroadcastChannel('channelName');
//监听消息
broadcastChannel.onmessage=function(e){
console.log('监听消息:',e.data);
};
document.getElementById('tab').onclick=function(){
window.open('xxx');
}
document.getElementById('l-btn').onclick=function(){
//发送消息
broadcastChannel.postMessage('测试,传送消息,我发送消息啦。。。');
}
document.getElementById('s-btn').onclick=function(){
//关闭
broadcastChannel.close();
}
</script>

面试装X:我知道的前端跨页面通信

Tips

  1. 监听消息除了接口是什么 .onmessage 这种方式,还可以 使用addEventListener来浏览器历史记录设置添加’mes前端开发需要掌握什么技术sage’监听,
  2. 关闭除了使用 Broadcast Channel 实例为我们提供的 close 方法来关闭 Broadcast Chan前端nel。我们还前端和后端的区别可取消或者修改相应的’mesHTTPSsage’事件监听。两者是有区html文件怎么打开别的:取消’mess接口文档age’监听只是让页面不对广播消息进行响应,Broadcast Channel 仍然存在;而调用 close 方浏览器法会切断与 Broadcast Channel 的浏览器的历史记录在哪连接,浏览器才能够尝试回收该对象,因为此时浏览器才会知道用户已经不需要使用广播频道了。
  3. 兼容性:如果不使用 IE 和 sf on iOS 浏览器,html标签属性大全兼容性还是可以的。

面试装X:我知道的前端跨页面通信

Service Worker

S接口是什么ervice Worker 是一个可接口测试用例设计以长期运行在后台的 Worker,能够实现与页面的双向通信。多页面共享间的 Service Worker 可以共享,将 Service Worker 作为消息的处理中心(中央站)即可实现广播效果。

语法

<divid="app"></div>
<buttonid="tab">新开Tab</button>
<buttonid="l-btn">发送消息</button>
<script>
/*判断当前浏览器是否支持serviceWorker*/
if('serviceWorker'innavigator){
/*当页面加载完成就创建一个serviceWorker*/
window.addEventListener('load',function(){
/*创建并指定对应的执行内容*/
/*scope参数是可选的,可以用来指定你想让serviceworker控制的内容的子目录。在这个例子里,我们指定了'/',表示根网域下的所有内容。这也是默认值。*/
navigator.serviceWorker.register('./serviceWorker.js',{scope:'./'})
.then(function(registration){
console.log('ServiceWorkerregistrationsuccessfulwithscope:',registration.scope);
})
.catch(function(err){
console.log('ServiceWorkerregistrationfailed:',err);
});
});
//监听消息
navigator.serviceWorker.addEventListener('message',function(e){
constdata=e.data;
console.log('我接受到消息了:',data);
});
document.getElementById('l-btn').onclick=function(){
navigator.serviceWorker.controller&&navigator.serviceWorker.controller.postMessage('测试,传送消息,我发送消息啦。。。');
};
}
</script>
/*监听安装事件,install事件一般是被用来设置你的浏览器的离线缓存逻辑*/
this.addEventListener('install',function(event){
/*通过这个方法可以防止缓存未完成,就关闭serviceWorker*/
event.waitUntil(
/*创建一个名叫V1的缓存版本*/
caches.open('v1').then(function(cache){
/*指定要缓存的内容,地址为相对于跟域名的访问路径*/
returncache.addAll(['./index.html']);
})
);
});
/*注册fetch事件,拦截全站的请求*/
this.addEventListener('fetch',function(event){
event.respondWith(
//magicgoeshere
/*在缓存中匹配对应请求资源直接返回*/
caches.match(event.request)
);
});
/*监听消息,通知其他Tab页面*/
this.addEventListener('message',function(event){
this.clients.matchAll().then(function(clients){
clients.forEach(function(client){
//这里的判断目的是过滤掉当前Tab页面,也可以使用visibilityState的状态来判断
if(!client.focused){
client.postMessage(event.data)
}
})
})
})

面试装X:我知道的前端跨页面通信

面试装X:我知道的前端跨页面通信

Tips

  1. Ser前端面试题vice workers 本质上充当 Web 应用程序、浏览器与接口类型网络(可用时)之间的代理服务器。所以本质上来说 Service Worker 并不自动具备“广播通信”的功能,需浏览器网站删除了怎么恢复要改造 Service Worker 添加些代码,将其接口是什么改造成消息中转站。接口类型在 Service Worker 中监听了message事件,获取页面发送的信息。然后通过 self.clients.matchAll() 获取当前注册了 Service Worker 的所有页面,通过调用每浏览器数据如何恢复个的 posthtml标签Message 方接口测试法,向页面发送消息。这样就把从一处(浏览器数据如何恢复某个Tab页面)收到的消息通知给了其他页面。
  2. 兼容性:IE 全军覆没,其他浏览器还行,整体来说一般。

面试装X:我知道的前端跨页面通信

open & opener

当我们 系统中通过 windo前端面试题w.open 打开一个新页面时,whttps认证indow.ophttps安全问题en 方法会返回一个被打开页面的引用,而被打开页面则可以通过 window.opener 获取到打开它的页面的引用(当然这是在没有指定noopener的情况下)前端和后端的区别

番外关于 noopener

<ahref="https://google.com"target="_blank">Google</a>

我们在系统中经常会这样使用 a 标签跳转到第三方网站,有时,当您单击网站上的链接时,该链接将在新选项卡中打开,但旧选项卡也会被重定向到其他网络钓鱼网站,它会要求您登录或开始将一些恶意软件下载到您的设备。这样存在一定的安全隐患,此时浏览器的历史在新打开的页面中可通过 window.opener 获取到源页面的 window 对象, 这就埋下了安全隐患。 比如:

  • 你自己的网站 A,点击如上链接打开了第三方网站 B。
  • 此时网站 B 可以通过 window.opener 获取到 A 网站的 window 对象。
  • 然后通过 window.opener.location.href = ‘w前端开发ww.baidu.com’ 这种形式跳转到一个钓鱼网站,泄露用户信息。

为了避免这样的问题,可以添加引入了 rel=”noopener” 属性, 这样新打开的页面便获取不到来源页面的 window 对象了, 此时 window.opener 的值是 null。

<ahref="https://google.com"rel="noopener"target="_blank">Google</a>

但是由于一些老的浏览器并不支持 noopener ,通常 noopener 和 noreferrer 会同时设置, rel=”noo接口类型pener noreferrer”。

html

回到主题,使用 window.opener 如前端和后端的区别何实现跨页面通信了。

  • 收集对象
//收集window对象:单个打开页面
constwindowOpen=window.open('xxx');
//收集window对象:多个打开页面,打开一个页面就需要将打开的window对象收集起来,以便于发布广播
constwindowOpens=[];
constwindowOpen=window.open('xxx');
windowOpens.push(windowOpen);
  • 发送消息
//发送消息:单个页面
windowOpen.postMessage(data);
//发送消息:多个页面
windowOpens.forEach((window)=>window.postMessage(data));
接受消息,对于接受消息来说,可能只是接受消息,但是可能接受消息的页面也打开了页面,这种情况需要将消息继续传递下去
window.addEventListener('message',function(e){
constdata=e.data;
console.log(data);
windowOpens.forEach((window)=>window.postMessage(data));
});

Tips

  1. 在收集到前端学什么的 window 对象中,可能有的 Tab 窗口被关闭了,这种情况下的接口crc错误计数 Tab 不需要进行消息传递。
  2. 对于接受消息的一方来说,需要继续传递消息,但是这里存在一个问题就是消息回传,可https域名能出现两者之间消息的死循环传递。
  3. 这种方式,类似击鼓传接口测试花,一个传一个,传递的消息从前往后,一条锁链浏览器推荐
  4. 但是如果页面不是通过一个页面打开的,而且直接打开的,或者从接口crc错误计数三方网站跳转的,那这条锁链将断开。所以这种方式基本只做了解,问题太多,可不做参考浏览器历史上的痕迹在哪里

完善的代码如下:

<buttonid="tab">新开Tab</button>
<buttonid="l-btn">发送消息</button>
<script>
//收集window对象:多个打开页面,打开一个页面就需要将打开的window对象收集起来,以便于发布广播
letwindowOpens=[];
document.getElementById('tab').onclick=function(){
//IP地址为本地的服务
constwindowOpen=window.open('http://127.0.0.1:5500/CrossPageCommunication/open&opener.html');
windowOpens.push(windowOpen);
}
document.getElementById('l-btn').onclick=function(){
constdata={};
console.log(windowOpens);
//发送消息之前,先进行已关闭Tab的过滤
windowOpens=windowOpens.filter((window)=>!window.closed);
if(windowOpens.length>0){
//数据打一个标记
data.tag=false;
data.message='测试,传送消息,我发送消息啦。。。'
windowOpens.forEach((window)=>window.postMessage(data));
}
if(window.opener&&!window.opener.closed){
data.tag=true;
window.opener.postMessage(data);
}
}
window.addEventListener('message',function(e){
constdata=e.data;
console.log('我接受到消息了:',data.message);
//避免消息回传
if(window.opener&&!window.opener.closed&&data.tag){
window.opener.postMessage(data);
}
//过滤掉已经关闭的Tab
windowOpens=windowOpens.filter((window)=>!window.closed);
//避免消息回传
if(windowOpens&&!data.tag){
windowOpens.forEach((window)=>window.postMessage(data));
}
});
</script>

面试装X:我知道的前端跨页面通信

SharedWorker

SharedWorker 接口代表一种特定类型的 worker,可以前端和后端哪个工资高前端几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。它们实现一个不同于普通 worker 的接口,具有不同的全局作用域, SharedWorkerGlobalScope。

语法

//创建共享线程对象
letworker=newSharedWorker("./sharedWorker.js");
//手动启动端口
worker.port.start();
//处理从worker返回的消息
worker.port.onmessage=function(val){
...
};
<buttonid="tab">新开Tab</button>
<buttonid="l-btn">点赞</button>
<p><span id="likedCount">还没有人点赞</span></span></p>
<script>
letlikedCountEl=document.querySelector("#likedCount");
letworker=newSharedWorker("./sharedWorker.js");
console.log('worker.port',worker.port);
worker.port.start();
//监听消息
worker.port.onmessage=function(val){
likedCountEl.innerHTML=val.data;
};
document.getElementById('tab').onclick=function(){
//IP地址为本地起的服务
constwindowOpen=window.open('http://127.0.0.1:5500/CrossPageCommunication/sharedWorker/index.html');
}
document.getElementById('l-btn').onclick=function(){
worker.port.postMessage('点赞了');
};
</script>
//./sharedWorker.js
leta=666;
console.log('shared-worker');
onconnect=function(e){
constport=e.ports[0];
console.log('shared-workerconnect');
//不能使用这种方式监听事件
//port.addEventListener('message',()=>{
//port.postMessage(++a);
//});
port.postMessage(a);
port.onmessage=()=>{
port.postMessage(++a);
};
console.log('当前点赞次数:',a);
};

面试装X:我知道的前端跨页面通信

Tip接口类型s

  1. 如果要使 SharedWor接口是什么ker 连接到多个不同的页面html5,这些页面必须是同源的(相同的协议、host 以及端口)。
  2. Shared Worker 在实现跨页面通信时的,它无法主动通html5知所有页面,需要刷新页面或者是定时任务来检查是否有新的消息。在例子中我是手动刷新的,当然可以使用 setInterval 来定时刷新。
  3. 如果需要调试 SharedWorker,使用 chrome://insphtml文件怎么打开ect/#workers

面试装X:我知道的前端跨页面通信

面试装X:我知道的前端跨页面通信

  1. sharedWorker.js 不能使用接口测试用例设计 .addEventListener 来监听 message 事件,监听无效。 兼容性一般。

面试装X:我知道的前端跨页面通信

总结

在上面列举了五种前端跨页面通信的方式浏览器哪个好,当然对前接口英文端来说远远不止这五种方式,还有其他方案例如:使用 hashchanhttps和http的区别ge、cookie、Websocket、postMessage 都是可以的。文章中只是列举了部分。并html是什么意思且文章中的方案都是针对同源的 Tab。

文章的前三种解决方式不论是 Broadcast Channel,还是 Service Worker ,或是 storage 事件,其都是“广播模式”:一个页面将消息通知给一个“中央站”,再由“中央站”通知给各个页面。

而对于 ope前端是什么工作n & opener 这种方式,类似击鼓传花,一个传一个,传递的浏览器数据如何恢复消息从前往后,一条锁链。但是如果页面html是什么意思不是通过一个页面打开的,而且直接打开接口测试用例设计的,或者从三方网站跳转的,那这条锁链将断开。

Shared Worker 的最大问题在于实现跨页面通信html文件怎么打开时的,它无法主动通知所有页面,需要刷新页面或者是定时任务来检查是否有新的消息,也就是需要配合轮询来使用。

最终在我们团队对于前端跨页面通信最后选择的解决方案是使用 onstorage,主要考量的三个方面:

  • 兼容性。浏览器支持度。
  • 通用性。能否覆盖需求、是否具有拓展性。
  • 便捷性。开发便捷程度。

其他方案在这三个方面来说都或多或少存在一些美中接口和抽象类的区别不足。

参考

  • www.w3cschool.cn/fetch_api/f…
  • developer.mozilla.org/zhhttps协议-CN/docs/…
  • /post/6844前端面试题90…
  • zhuanlan.zhihu.com/p/81237384
  • developer.mozilla.org/en-US/docs/…
  • /post/68前端和后端4490…
  • developer.mozilla.org/zh-CN/docs/…
  • de前端是什么工作veloper.mozilla.o浏览器rg/en-US/docs/…
  • zhuanlan.zhihu.com/p/366736912
  • blog.bhanuteja.dev/noo浏览器推荐pener-no…
  • blog.csdn.net/huangpb123html5/…
  • my.oschina.net/ahaoboy/blo…