在前端不同标签页进行广播通信(基于BroadcastChannel)

372 阅读3分钟

介绍

在浏览器中为开发者提供了BroadcastChannelAPI,可以在不同标签页之间进行广播通信。其实等于是在浏览器的级别,针对当前同域的页面,做了一个跨页面窗口级别的EventEmitter

如果你对实现EventEmitter感兴趣,可以点击笔者的这篇文章查看如何实现一个EventEmitter

大橙子认为它也是发布订阅模式的一种实践方式~~

实践

创建频道

通过创建一个BroadcastChannel实例来新建一个频道。

!!请注意!!

需要在实例化的时候传入频道名称,所有监听这个频道的页面,都需要基于该名称来监听这个频道(因此建频道名称需要唯一)。

举个例子: 如果需要在电视上收看CCTV-1频道,那么在收看频道时,我们需要选择CCTV-1频道,并且这个名称肯定是唯一的,不可能有别的频道放着相同的节目也叫CCTV-1(有的话那叫李鬼(¬_¬))。

const bc = new BroadcastChannel('orange-channel');

你可以通过实例化后bcname属性来获取名称:

console.log(bc.name) // orange-channel

EventEmitter的角度来看,其实等于是在全局注册了一个事件类型

监听及发送消息

监听消息和错误

在实例化完成BroadcastChannel后,就可以通过addEventListener监听messagemessageerror事件,来获取消息和错误:

const bc = new BroadcastChannel('cctv1');

bc.addEventListener('message', (event) => {
  console.log(event.data);
});

bc.addEventListener('messageerror', (event) => {
  console.error(event);
});

EventEmitter的角度来看,通过浏览器的addEventListener实现了监听功能

发送消息

通过实例的postMessage方法,可以向所有监听该频道(name相同)的页面发送消息:

bc.postMessage('hello world!')

EventEmitter的角度来看,实现了触发事件功能

销毁频道

如果你已经不需要监听该频道,请一定要使用close方法!!

因为调用close后当前实例化资源会被浏览器回收。

bc.close()

EventEmitter的角度来看,实现了销毁监听功能。

测试页面

创建一个index.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>BroadcastChannel Demo页面</title>
</head>
<body>
<div>
    <span id="channel"></span><br>
    <span id="message">当前频道暂无消息</span>
</div>
<button id="post">发送消息</button>
<button id="close">关闭频道</button>
<script>
    const bc = new BroadcastChannel('orange-tv');
    const tip = document.getElementById('channel');

    tip.innerHTML = `当前你正在收听频道的是:${bc.name}`;

    bc.addEventListener('message', (event) => {
        document.getElementById('message').innerHTML = `当前频道的消息是:${event.data}`;
    });

    document.getElementById('post').addEventListener('click', () => {
        bc.postMessage(`hello world, ${new Date().toLocaleString()}`);
    });

    document.getElementById('close').addEventListener('click', () => {
        bc.close();
    });
</script>
</body>
</html>

在webstorm中,你可以基于该页面打开3个标签页

image.png 在第一个打开的页面中,点击发送消息按钮👇🏻 image.png 可以看到其余的两个页面中展示了刚刚点击按钮时的时间

image.png

如果在最后一个打开的页面中,点击了关闭频道按钮。再回到第一个打开的页面中,点击发送消息按钮

此时可以发现:第二个页面更新了时间,但是由于第三个页面已经关闭了频道,因此没有接收到最新的信息。

请注意!!

有些同学可能误认为将频道close掉后,感觉上来说点击第一个页面的发送消息应该不能执行成功。

事实上这个close和你关电视的感觉差不多,它只会将当前的监听关闭,并不会影响这个频道本身,如果其它页面有以同样name命名的频道还在,依旧可以发布消息。

当然这个浏览器API并不是所有浏览器都支持,使用前请先查阅兼容性!! 👉🏻caniuse.com/broadcastch…

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看活动详情