如何在JavaScript中使用BroadcastChannel API

news/2024/7/7 19:08:35

The BroadcastChannel API is a new web platform API that lets you communicate between different windows/tabs/iframes of the same origin. Using BroadcastChannel may sound fancy and daunting but it is super easy and useful.

BroadcastChannel API是一个新的Web平台API,可让您在同一来源的不同窗口/标签/ iframe之间进行通信。 使用BroadcastChannel听起来可能很花哨和令人生畏,但它非常简单实用。

为什么要使用BroadcastChannel API (Why use the BroadcastChannel API)

Try to log into one of your favorite websites (I tried it on youtube.com). Then, open in a separate tab the same website. Normally you will be logged into both pages. Then log out on one of your tabs. On most sites, it will look like you are logged in one page and logged off the other.

尝试登录您最喜欢的网站之一(我在youtube.com上尝试过)。 然后,在同一网站的单独标签中打开。 通常,您将登录到两个页面。 然后注销您的选项卡之一。 在大多数站点上,您好像登录一个页面,然后注销另一页面。

Your windows are in different states: logged-in vs logged-out. That’s not great and if you are a maniac tabber (like me) it can lead to some confusion.

您的窗口处于不同状态:已登录与已注销。 那不是很好,如果您是疯子(像我一样),可能会导致一些混乱。

This can even be a security issue. Imagine your user is in a coffee shop using the company dashboard. He logs off to take a toilet break and leaves the computer on. If the application was opened in multiple tabs one could access the data available in the other tabs (on screen or maybe some JWT token).

这甚至可能是一个安全问题。 假设您的用户使用公司的仪表板在咖啡店里。 他注销要上厕所休息,然后打开计算机电源。 如果在多个选项卡中打开了应用程序,则可以访问其他选项卡中的可用数据(在屏幕上或某些JWT令牌中)。

BroadcastChannel API代码 (BroadcastChannel API Code)

Here’s a very simple example that you can copy paste in a local HTML file:

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

<!DOCTYPE html>

<body>
  <!-- The title will change to greet the user -->
  <h1 id="title">Hey</h1>
  <input id="name-field" placeholder="Enter Your Name"/>
</body>

<script>

var bc = new BroadcastChannel('gator_channel');

(()=>{
  const title = document.getElementById('title');
  const nameField = document.getElementById('name-field');
  const setTitle = (userName) => {
    title.innerHTML = 'Hey ' + userName;
  }

  bc.onmessage = (messageEvent) => {
    // If our broadcast message is 'update_title' then get the new title from localStorage
    if (messageEvent.data === 'update_title') {
      // localStorage is domain specific so when it changes in one window it changes in the other
      setTitle(localStorage.getItem('title'));
    }
  }

  // When the page loads check if the title is in our localStorage
  if (localStorage.getItem('title')) {
    setTitle(localStorage.getItem('title'));
  } else {
    setTitle('please tell us your name');
  }

  nameField.onchange = (e) => {
    const inputValue = e.target.value;
    // In the localStorage we set title to the user's input
    localStorage.setItem('title', inputValue);
    // Update the title on the current page 
    setTitle(inputValue);
    // Tell the other pages to update the title
    bc.postMessage('update_title');
  }
})()
</script>

This page has a title and an input. When the user enters her name in the input we store the name in the local storage under the key userName. Then, we set the title of our application to 'Hey' + userName. So if the user’s name is Sarah the page will show “Hey Sarah”.

该页面具有标题和输入。 当用户在输入中输入她的姓名时,我们会将名称存储在本地存储中的键userName 。 然后,我们将应用程序的标题设置为'Hey' + userName 。 因此,如果用户名为Sarah则页面将显示“ Hey Sarah”。

If we didn’t have a BroadcastChannel when the user enters her name in one window it wouldn’t update the other window. Without the broadcast channel in our code, the user would have to refresh the second window to update the title.

如果当用户在一个窗口中输入她的名字时我们没有BroadcastChannel ,则不会更新另一个窗口。 在我们的代码中没有广播频道的情况下,用户将不得不刷新第二个窗口以更新标题。

So in our first line, we create a BroadcastChannel called “gator_channel”. We then create a message receiver using the onmessage method. We set onmessage to a function that takes one argument (aka an event message). Then, in our code, we check that the name of the message is update_title. If so, we extract the user name from the local storage.

因此,在第一行中,我们创建了一个名为“ gator_channel”的BroadcastChannel 。 然后,我们使用onmessage方法创建一个消息接收器。 我们将onmessage设置为带有一个参数的函数(又称事件消息)。 然后,在我们的代码中,检查消息的名称是否为update_title 。 如果是这样,我们从本地存储中提取用户名。

Whenever we call postMessage on the broadcast channel, it will call onmessage in the other windows. So if I input Jack in window 1, then window 1 will call bc.postMessage('updated_title'). This will activate onmessage on window 2 and any other window opened on the same origin.

每当我们在广播频道上调用postMessage时,它将在其他窗口中调用onmessage 。 因此,如果我在窗口1中输入Jack,则窗口1将调用bc.postMessage('updated_title') 。 这将激活窗口2和在相同起点上打开的任何其他窗口上的onmessage

它会在哪里工作 (Where it Will Work)

Unlike other APIs such as window.postMessage, you don’t need to know anything about the other windows or tabs opened. The Broadcast Channel will work on any tab or window which is in the same origin (same scheme, host and port).

与其他API(例如window.postMessage ,您不需要了解其他有关打开的其他窗口或选项卡的信息。 广播频道将在相同来源(相同的方案,主机和端口)的任何选项卡或窗口上工作。

This means that you can broadcast messages from https://alligator.io/ to https://alligator.io/js/broadcast-channels. All you need is to have a BroadcastChanel object on both pages using the same channel name:

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

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

If the hosts are different it won’t work:

如果主机不同,则无法使用:

  • https://alligator.io

    https://alligator.io

  • https://www.alligator.io

    https://www.alligator.io

If the ports are different it won’t work:

如果端口不同,将无法使用:

  • https://alligator.io

    https://alligator.io

  • https://alligator.io:8080

    https://alligator.io:8080

If the schemes are different it won’t work. That is similar to different ports since the standard is that http and https respectively use port 80 and 443:

如果方案不同,它将无法正常工作。 这类似于不同的端口,因为标准是http和https分别使用端口80和443:

  • http://alligator.io

    http://alligator.io

  • https://alligator.io

    https://alligator.io

Broadcast channels will not work if one of the windows is in incognito mode or across browsers (e.g. Firefox to Chrome).

如果其中一个窗口处于隐身模式或跨浏览器(例如Firefox至Chrome),则广播频道将不起作用。

浏览器兼容性 (Browser compatibility)

According to (caniuse.com)[https://caniuse.com/#feat=broadcastchannel], the BroadcastChannel API is available to about 75.6% of users. Safari and Internet Explorer don’t have any support for it yet.

根据(caniuse.com)[ https://caniuse.com/#feat=broadcastchannel]的说法,约有75.6%的用户可以使用BroadcastChannel API。 Safari和Internet Explorer尚无任何支持。

To my knowledge, the most popular polyfill is this one. You can use it almost exactly like the BroadcastChannel API. If it detects that the BroadcastChannel API is available it will use it automatically for faster results. Otherwise, it will use IndexedDB or LocalStorage.

据我所知,最受欢迎的polyfill就是这种 。 您几乎可以像BroadcastChannel API一样使用它。 如果它检测到BroadcastChannel API可用,它将自动使用它以获得更快的结果。 否则,它将使用IndexedDB或LocalStorage。

我们可以传递什么信息? (What Messages Can We Pass?)

You can pass anything that can be cloned using the structured clone algorithm. That includes almost everything except symbols:

您可以传递可以使用结构化克隆算法克隆的任何内容。 其中几乎包括符号以外的所有内容:

  • All primitive types except symbols (Boolean, Null, Undefined, Number, BigInt, String)

    除符号外的所有基本类型(布尔,空,未定义,数字,BigInt,字符串)
  • Boolean and String objects

    布尔和字符串对象
  • Dates

    日期
  • Regular Expressions

    常用表达
  • Blobs

    斑点
  • Files, FileLists

    文件,文件列表
  • ArrayBuffers, ArrayBufferViews

    ArrayBuffers,ArrayBufferViews
  • ImageBitmaps, ImageDatas

    ImageBitmaps,ImageDatas
  • Arrays, Objects, Maps and Sets

    数组,对象,地图和集合

If you try sending something like a Symbol, you will get an error on the sending side.

如果尝试发送类似符号的内容,则会在发送方收到错误消息。



Let’s update our code and use objects instead of strings.

让我们更新代码并使用对象代替字符串。

bc.onmessage = (messageEvent) => {
    const data = messageEvent.data
    // If our broadcast message is 'update_title' then get the new title from localStorage
    switch (data.type) {
      case 'update_title':
        if (data.title){
          setTitle(data.title);
        }
        else
          setTitle(localStorage.getItem('title'));
        break
      default:
        console.log('we received a message')
    }
  };
  // ... Skipping Code
  bc.postMessage({type: 'update_title', title: inputValue});

广播频道可以做的事情 (Things You Can Do with Broadcast Channels)

There are many things we can imagine. The most obvious use case is to share states. For example, if you use something like Flux or Redux to manage your state, you can broadcast a message so that your store remains the same across tabs. We can also imagine building something similar for state machines.

我们可以想象很多事情。 最明显的用例是共享状态。 例如,如果您使用Flux或Redux之类的东西来管理状态,则可以广播一条消息,以便您的商店在各个标签之间保持不变。 我们还可以想象为状态机构建类似的东西。

We saw that we can also send large files in different formats. We might be able to save some bandwidth by sharing large files such as images across tabs.

我们看到,我们还可以发送不同格式的大文件。 通过跨选项卡共享大文件(例如图像),我们也许可以节省一些带宽。

关闭广播频道 (Closing a Broadcast Channel)

Closing a broadcast channel is super easy. You simply have to run the close method on your broadcast channel:

关闭广播频道非常容易。 您只需要在广播频道上运行close方法:

bc.close()

You might want to close or open channels depending on the state of your application. For instance, when you are logged-in you might have a specific channel to share your application’s state. You might want to close that channel when you log out.

您可能要关闭或打开通道,具体取决于应用程序的状态。 例如,当您登录时,您可能具有特定的频道来共享应用程序的状态。 您可能想在注销时关闭该频道。

翻译自: https://www.digitalocean.com/community/tutorials/js-broadcastchannel-api


http://www.niftyadmin.cn/n/3648916.html

相关文章

Android5.0 与 4.x的不同

之前开发的项目在4.X完美运行&#xff0c;可是用户升级到5.0以上就出现莫名的bug。 以下是修改bug中总结的差异化&#xff01;&#xff08;持续更新&#xff09; 总体感觉5.0以后对程序员的编码要求更高了&#xff0c;没有4.X系列那么随意了。 1&#xff0c;此处View 必须是Lin…

使用Simplur在JavaScript中进行字符串多元化

Handling plural/singular forms of nouns in English can be difficult in software. Using a library called Simplur provides you with a simple JavaScript utility to solving this problem! 在软件中很难处理名词的复数/单数形式。 使用名为Simplur的库为您提供了一个简…

安卓5.0六大最烦人问题与解决方法

Android 5.0 Lollipop虽然带来了许多重要的升级和优化&#xff0c;但和所有操作系统一样&#xff0c;它也难免会带着一些缺陷和漏洞。最近&#xff0c;科技网站Digital Trends就汇总了Android 5.0身上6个最为烦人的问题&#xff0c;以及相应的解决办法。 应用崩溃、启动器重绘、…

JavaScript字符串匹配方法快速指南

String.prototype.match() (aka: the match method on strings) can allow you to switch out strings or set conditions if a string or any data is matched. It then stores that data in a new array. String.prototype.match() (又名&#xff1a;字符串的match方法)可以让…

软件测试管理--前言

国内IT公司的软件产品质量较差已经是一个不争的事实。测试作为质量管理的一个方面&#xff0c;更是重灾区。目前国内市场上有关测试方面的书籍基本都是翻译的&#xff0c;因此很多都不符合我国软件管理的发展现状。国内的测试工程师大多是没有开发和测试经验的新手&#xff0c;…

Android 应用程序升级到 5.0 需要注意的问题

Android 5.0&#xff0c;代号 Lollipop&#xff0c;源码终于在2014年12月3日放出&#xff0c;国内一大批厂商跟进。最大的改变是默认使用 ART(Android Runtime) &#xff0c;替换了之前的 Dalvik 虚拟机&#xff0c;提出了 Material Design 界面风格。之前发布的 app 可能需要作…

[dotNET]COM组件转换成.NET组件{ZT}

原作者&#xff1a;http://www.cnblogs.com/wubn/archive/2004/09/29/47997.aspx利用类型库导入器(Type Library Importer)可以将其包装成一个.NET组件&#xff0c;然后就可以像使用.NET组件一样使用它了。 .NET框架只是提供了一个包装&#xff0c;并没有真正改变原有的对象1.找…

Java中必须了解的常用类

包装类 int、float、double、boolean、char等都不具备对象的特性&#xff0c;例如基本方法不能调用&#xff0c;功能简单等&#xff0c;为了让基本数据类型具备对象的特性&#xff0c;java为每个数据提供了一个包装类&#xff0c;这样我们就可以操作对象那样操作数据了。 J…