探索广播频道 API

2025-06-08

探索广播频道 API

你知道快餐店里那些数字菜单板吗?嗯,去年我就开始做其中的一个。

好的,但是这与广播频道 API 有什么关系?

一些背景知识

在我们的具体案例中,菜单板是一个 React Web 应用,运行在餐厅的 Chromebox 上。它支持两个显示器,我们根据 URL 路由控制它显示哪个菜单页面。

两个浏览器窗口显示不同的菜单页面

其中一个需求是我们需要为菜单中的某些元素添加动画效果,但有一个问题。动画必须在各个显示屏上同步。我们无法随时启动动画循环。我们需要一种方式让两个页面相互通信,以便同时启动它们的计时器。

输入广播频道 API

什么是广播频道 API?

它是一个 Web API,允许同源的浏览上下文(即窗口、选项卡、iframe、webviews)之间进行基本通信。

两个浏览器窗口通过广播信道进行通信

首先创建一个BroadcastChannel对象并为其命名。如果已存在同名的频道,它将加入该频道。

const channel = new BroadcastChannel("channel_name")
Enter fullscreen mode Exit fullscreen mode

要发送消息,您可以调用postMessage()创建的对象上的方法,该方法将任何对象作为参数。

channel.postMessage("is this thing on?")
Enter fullscreen mode Exit fullscreen mode

这将向message每个加入频道的上下文发送一个事件。然后,我们可以使用onmessage事件处理程序针对该事件运行一个函数。

channel.onmessage = ev => {
  console.log(ev.data)
}
// is this thing on?
Enter fullscreen mode Exit fullscreen mode

要断开与通道的连接,请调用close()对象上的方法。

channel.close()
Enter fullscreen mode Exit fullscreen mode

回到我们的应用程序

我们能够利用此 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" })
Enter fullscreen mode Exit fullscreen mode

玩一玩

我在 Codesandbox 上做了一个简化的 demo。以下是它的简短预览:

两个浏览器窗口的动画 gif,显示同步计时器

很酷吧?

警告

并非所有浏览器都原生支持此功能。幸运的是,有一个名为broadcast-channel的 npm 包,它具有相同的 API,并在支持该功能的浏览器中使用原生实现。此外,它也允许您在 Node 中使用它!


封面照片由Prince Abid拍摄

鏂囩珷鏉ユ簮锛�https://dev.to/bernardop/exploring-the-broadcast-channel-api-i57
PREV
10 个适合无聊程序员的有趣 Web 开发项目创意
NEXT
使用 AMD GPU 自托管运行 Ollama 和 Open WebUI