Using JavaScript and The Broadcast Channel API

For Browser Context Communication Between Tabs

gravity well
Jan 13 · 5 min read
Photo by Kadir Celep on Unsplash

In a previous article we discussed cross-origin communication using window.postMessage().

In this article, I’d like us to explore postMessage() again, but as it applies to communication within the same browsing context or same origin.

This is performed using the Broadcast Channel API and channel.postMessage().

To be more specific, this allows for communication between windows, tabs, iframes, web workers, and service workers. Messages posted to a given channel are delivered to all listeners of that channel.

We will focus on windows/tabs.

Syntax

Working with the broadcast channel involves three parts.

  • Creating the broadcast channel Object.
const bc = new window.BroadcastChannel('channel_name');
  • Posting a message to be broadcast using postMessage().
bc.postMessage('message_data');

As with our cross-origin postMessage, the message_data is serialized using the structured clone algorithm, so the data being broadcast can be quite complex. But it does disallow for the sending of functions.

  • Receiving the message using the onmessage event handler.
bc.onmessage =(message)=> { do_something; }

The actual message is in message.data.

Note that a message won’t broadcast to itself. So if you have an onmessage event listener on the same page as the page that initiated the postMessage() on that channel, that onmessage event will not fire. It will fire, however, if postMessage() is initiated from another page.

broadcast flow

Our Scenario

For our demonstration, our scenario will be that the user has opened up one or more instances of our application, each appearing on a different tab.

  1. We will create a web page (our application) and then duplicate it in the browser (as many times as desired.)
  2. When a “Start Action” button is clicked, a message will show on the current page (via a function, setMsg()) as well as on each page (tab) that has the onmessage handler for the channel.

Note: A random number will be used to generate one of two messages.

Create the following page. We will then we will test it and then break it down.

Index.html

<!DOCTYPE html>
<html>
<head>
<title>My Great Application</title>
<meta charset="utf-8" />
<script>
// Set up broadcast channel
const bc=new window.BroadcastChannel('sample_channel');

function doAction(){
// Action that will be done on current and other pages
// The message will be broadcast to all tabs
// it will also be displayed on the current
// page using a setMsg function since the
// source of the postMessage does not receieve
// the message.
// Random action: answer or call
let ran=Math.floor(Math.random() * 2);

let msg={};
if (Number(ran)===0){
msg={action: 'answer',
phone: '555-1212'
}
}else{
msg={action: 'call',
phone: '444-2233'
}
}

// broadcast message to others tabs
bc.postMessage(msg);

// show message on this page since
// it will not be received from
// page that initiated postMessage
setMsg(msg);
}

// Handler for accepting messages that are broadcast
bc.onmessage=(message)=>{

let txt = document.querySelector('#txtmsg');
if (message.data.action==='answer'){
txt.value=`Answer ${message.data.phone}`;
}else{
txt.value=`Call ${message.data.phone}`;
}

}
// function to handle messages for page that
// initiated postMessage
function setMsg(msg){
let txt = document.querySelector('#txtmsg');
if (msg.action==='answer'){
txt.value=`Answer ${msg.phone}`;
}else{
txt.value=`Call ${msg.phone}`;
}
}

</script>
</head>
<body>
<form>
<fieldset>
<input type='button' id='btnstart' value='Start Action' onclick='doAction();' />
Message: <input type='text' id='txtmsg' />
</fieldset>
</form>
</body>
</html>

Testing it

Test in the following ways.

  1. Open Index.html and click “Start Action”. You should see one of two random messages. Close the tab.
  2. Open Index.html and duplicate the tab. Click the “Start Action” on either page. The message should appear on both pages. You can click “Start Action” as many times as you desire, from whichever tab you desire, to verify the message is broadcast. Close the tabs when done.
  3. Open Index.html and duplicate the tab as many times as desired. Click the “Start Action” on any page. The message should appear on all pages. Repeat as desired.

How It Works

  1. The broadcast channel, bc, is established on each page (one page in our case. The page will be duplicated.)
// Set up broadcast channel
const bc=new window.BroadcastChannel('sample_channel');

This needs to be on each page that is to broadcast or receive a message.

2. Each page that is to receive the message should also have the bc.onmessage handler (bc being the name of the broadcast channel.) You will see the onmessage handler. It does the work of putting a message in the textbox. It receives the broadcasted message in the “message” parameter. The information is in message.data.

// Handler for accepting messages that are broadcast
bc.onmessage=(message)=>{

let txt = document.querySelector('#txtmsg');
if (message.data.action==='answer'){
txt.value=`Answer ${message.data.phone}`;
}else{
txt.value=`Call ${message.data.phone}`;
}

}

3. In our example, we have a doAction() function, invoked by the “Start Action” button that performs the broadcasting by way of the postMessage() method, to all other pages in the browsing context — same origin.

Since this page’s onmessage handler will not be invoked (it is this source of the postMessage), we also have a function, setMsg(), that handles the message for the message initiating page.

All other pages will rely on their onmessage handler attached to the broadcast channel.

function doAction(){
// Action that will be done on current and other pages
// The message will be broadcast to all tabs
// it will also be displayed on the current
// page using a setMsg function since the
// source of the postMessage does not receieve
// the message.
// Random action: answer or call
let ran=Math.floor(Math.random() * 2);

let msg={};
if (Number(ran)===0){
msg={action: 'answer',
phone: '555-1212'
}
}else{
msg={action: 'call',
phone: '444-2233'
}
}

// broadcast message to others tabs
bc.postMessage(msg);

// show message on this page since
// it will not be received from
// page that initiated postMessage
setMsg(msg);// For the initiating page
}

Testing Note:

To verify that the other tabs are having their message set by the onmessage handler and not by setMsg(), you may want to comment out setMsg(), open multiple tabs and click “Start Action”.

The initiating page will not have the message, but all others will!

Conclusion

And there you have it. If you want each page in a browsing context to share information, you can broadcast to each page using postMessage() as long as each page has the broadcast channel and a handler.

Thank you for reading and happy coding!

You may also enjoy.

JavaScript in Plain English

Learn the web's most important programming language.

gravity well

Written by

Self-Employed Software Developer, Trainer, Consultant. Keeping up to date. I’ve noticed in over 28 years of programming, one’s current skills have a shelf life.

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade