探索广播频道 API
你知道快餐店里那些数字菜单板吗?嗯,去年我就开始做其中的一个。
好的,但是这与广播频道 API 有什么关系?
一些背景知识
在我们的具体案例中,菜单板是一个 React Web 应用,运行在餐厅的 Chromebox 上。它支持两个显示器,我们根据 URL 路由控制它显示哪个菜单页面。
其中一个需求是我们需要为菜单中的某些元素添加动画效果,但有一个问题。动画必须在各个显示屏上同步。我们无法随时启动动画循环。我们需要一种方式让两个页面相互通信,以便同时启动它们的计时器。
输入广播频道 API。
什么是广播频道 API?
它是一个 Web API,允许同源的浏览上下文(即窗口、选项卡、iframe、webviews)之间进行基本通信。
首先创建一个BroadcastChannel
对象并为其命名。如果已存在同名的频道,它将加入该频道。
const channel = new BroadcastChannel("channel_name")
要发送消息,您可以调用postMessage()
创建的对象上的方法,该方法将任何对象作为参数。
channel.postMessage("is this thing on?")
这将向message
每个加入频道的上下文发送一个事件。然后,我们可以使用onmessage
事件处理程序针对该事件运行一个函数。
channel.onmessage = ev => {
console.log(ev.data)
}
// is this thing on?
要断开与通道的连接,请调用close()
对象上的方法。
channel.close()
回到我们的应用程序
我们能够利用此 API 在两个显示器之间进行通信,并确保它们同时开始动画循环。请记住,每个显示器的“启动”时间略有不同,因此我们需要提前进行一些协商,以了解它们何时准备就绪。
基本逻辑如下:
/**
* In this example I will refer to the first display to finish
* booting up as "display 1". The second one to be ready will
* be "display 2".
*/
// display 1 creates the channel; display 2 joins it
const syncChannel = new BroadcastChannel("animation-sync")
syncChannel.onmessage = ({ data }) => {
switch (data.type) {
// display 1 receives the "READY" message from display 2
// and posts a message to start setting things up
case "READY": {
syncChannel.postMessage({ type: "START" })
break
}
// display 2 receives the "START" message
case "START": {
// record the current time (just to be safe we pad it 5s
// to allow display 1 to receive the next message)
const syncTime = new Date().getTime() + 5000
// outside function that schedules the animations
scheduleAnimations(syncTime)
// send "SYNC" message to display 1 with the syncTime
syncChannel.postMessage({ type: "SYNC", syncTime })
break
}
// display 1 receives the "SYNC" message with the syncTime
case "SYNC": {
scheduleAnimations(data.syncTime)
break
}
default:
break
}
}
// display 2 sends the "READY" message to display 1
animationSyncChannel.postMessage({ type: "READY" })
玩一玩
我在 Codesandbox 上做了一个简化的 demo。以下是它的简短预览:

很酷吧?
警告
并非所有浏览器都原生支持此功能。幸运的是,有一个名为broadcast-channel的 npm 包,它具有相同的 API,并在支持该功能的浏览器中使用原生实现。此外,它也允许您在 Node 中使用它!
封面照片由Prince Abid拍摄
鏂囩珷鏉ユ簮锛�https://dev.to/bernardop/exploring-the-broadcast-channel-api-i57