如何在 JavaScript 中使用广播频道 API

BroadcastChannel API是一个新的Web平台API,允许您在相同来源的不同窗口/标签/iframes之间进行通信。

为什么要使用 BroadcastChannel API

尝试登录你最喜欢的网站之一(我在youtube.com上尝试过)。然后,在单独的页面中打开相同的网站。通常你会登录到两个页面。然后登录到你的页面之一。在大多数网站上,它看起来像你在一个页面上登录,在另一个页面上登录。

你的窗口处于不同的状态:登录与退出,这不是很棒,如果你是一个疯狂的骗子(像我一样),它可能会导致一些混乱。

这甚至可能是一个安全问题. 想象你的用户是在一家咖啡店使用公司的仪表板。 他登录取厕所休息并离开计算机打开. 如果应用程序在多个卡上打开,可以访问其他卡(屏幕上或某些JWT代币)中可用的数据。

广播频道API代码

以下是一个非常简单的例子,您可以将粘贴复制到本地HTML文件中:

 1<!DOCTYPE html>
 2
 3<body>
 4  <!-- The title will change to greet the user -->
 5  <h1 id="title">Hey</h1>
 6  <input id="name-field" placeholder="Enter Your Name"/>
 7</body>
 8
 9<script>
10
11var bc = new BroadcastChannel('gator_channel');
12
13(()=>{
14  const title = document.getElementById('title');
15  const nameField = document.getElementById('name-field');
16  const setTitle = (userName) => {
17    title.innerHTML = 'Hey ' + userName;
18  }
19
20  bc.onmessage = (messageEvent) => {
21    // If our broadcast message is 'update_title' then get the new title from localStorage
22    if (messageEvent.data === 'update_title') {
23      // localStorage is domain specific so when it changes in one window it changes in the other
24      setTitle(localStorage.getItem('title'));
25    }
26  }
27
28  // When the page loads check if the title is in our localStorage
29  if (localStorage.getItem('title')) {
30    setTitle(localStorage.getItem('title'));
31  } else {
32    setTitle('please tell us your name');
33  }
34
35  nameField.onchange = (e) => {
36    const inputValue = e.target.value;
37    // In the localStorage we set title to the user's input
38    localStorage.setItem('title', inputValue);
39    // Update the title on the current page 
40    setTitle(inputValue);
41    // Tell the other pages to update the title
42    bc.postMessage('update_title');
43  }
44})()
45</script>

这个页面有一个标题和一个输入.当用户在输入中输入时,我们将其名称存储在本地存储中,在userName键下。

如果我们没有一个BroadcastChannel,当用户在一个窗口中输入她的名字时,它不会更新另一个窗口。

因此,在第一行中,我们创建了一个名为gator_channelBroadcastChannel。然后我们使用onmessage方法创建一个消息接收器。我们将onmessage设置为一个函数,该函数需要一个参数(也称为事件消息)。

每当我们在广播频道上调用postMessage时,它会在其他窗口中调用onmessage。所以,如果我在窗口 1中输入Jack,那么窗口 1会调用bc.postMessage(更新_标题)。

它将工作在哪里

與「window.postMessage」等其他 API 不同,您不需要知道其他開啟的窗口或頁面。

这意味着您可以从 https://alligator.io/ 广播消息到 https://alligator.io/js/broadcast-channels. 您所需要的只是在使用相同的频道名称的两页上有一个 BroadcastChanel 对象:

1const bc = new BroadcastChannel('alligator_channel');
2bc.onmessage = (eventMessage) => {
3  // do something different on each page
4}

如果主机不同,它不会起作用:

如果端口不同,它不会起作用:

这是类似于不同的端口,因为标准是 http 和 https 分别使用端口 80 和 443:

如果其中一个窗口处于匿名模式或跨浏览器(例如,Firefox到Chrome)时,广播频道将无法工作。

浏览器兼容性

根據 (caniuse.com)https://caniuse.com/#feat=broadcastchannel,BroadcastChannel API 可供大約 75.6% 的用戶使用。 Safari 和 Internet Explorer 尚未提供任何支援。

據我所知,最受歡迎的多重檔案是 這一個。你可以使用它幾乎完全像BroadcastChannel API。如果它發現BroadcastChannel API可用,它會自動使用它以獲得更快的結果。

我们可以传递哪些信息?

您可以使用结构化克隆算法传递可克隆的任何东西,其中包括除了符号之外的几乎所有东西:

所有原始类型除符号(Boolean、Null、Undefined、Number、BigInt、String)

  • Boolean 和 String 对象 *日期 *常规表达式
  • Blobs
  • 文件、 文件列表
  • ArrayBuffers、 ArrayBufferViews
  • ImageBitmaps、 ImageDatas
  • Arrays、 Objects、 Maps 和 Sets

如果您尝试发送象征类似的东西,则会收到发送侧的错误。


让我们更新我们的代码,使用对象而不是字符串。

 1bc.onmessage = (messageEvent) => {
 2    const data = messageEvent.data
 3    // If our broadcast message is 'update_title' then get the new title from localStorage
 4    switch (data.type) {
 5      case 'update_title':
 6        if (data.title){
 7          setTitle(data.title);
 8        }
 9        else
10          setTitle(localStorage.getItem('title'));
11        break
12      default:
13        console.log('we received a message')
14    }
15  };
16  // ... Skipping Code
17  bc.postMessage({type: 'update_title', title: inputValue});

你可以用广播频道做的事情

我们可以想象很多事情。最明显的用例是共享状态.例如,如果你使用Flux或Redux来管理你的状态,你可以播放消息,以便你的商店在各个选项卡上保持相同。

我们看到,我们也可以以不同的格式发送大文件,我们可能会通过共享大文件(如图像)在卡片中节省一些带宽。

关闭一个广播频道

关闭一个广播频道非常容易. 你只需要在你的广播频道上运行关闭方法:

1bc.close()

您可能需要关闭或打开渠道,取决于您的应用程序的状态,例如,当您登录时,您可能有一个特定的渠道来共享您的应用程序的状态。

Published At
Categories with 技术
Tagged with
comments powered by Disqus