/

The Channel Messaging API: Facilitating Communication Between iframes and Workers

The Channel Messaging API: Facilitating Communication Between iframes and Workers

The Channel Messaging API provides a means of communication between iframes and the main document thread. This allows for the passing of messages between different contexts within the same document.

Introduction to Channel Messaging API

The Channel Messaging API enables communication between:

  • The document and an iframe
  • Two iframes
  • Two documents

How it works

To initialize a message channel, you can use the new MessageChannel() method:

1
const channel = new MessageChannel();

The channel has two properties: port1 and port2. These properties represent the ports used by the channel creator and receiver, respectively. Since the channel is bidirectional, both ends can send and receive messages.

To send a message, you can utilize the otherWindow.postMessage() method, where otherWindow refers to the target browsing context. This method requires the message, origin, and port as parameters. For example:

1
2
3
const data = { name: 'Flavio' };
const channel = new MessageChannel();
window.postMessage(data, [channel.port2]);

Messages can take various forms, including primitive types, arrays, object literals, strings, dates, regular expressions, blobs, files, file lists, array buffers, array buffer views, form data, image data, maps, and sets.

The origin parameter represents the URI of the target window. You can use '*' for less strict checking or specify a specific domain. Using '/' allows you to set a same-domain target without specifying the domain.

The receiving browsing context listens for messages using the message event:

1
2
3
self.addEventListener('message', event => {
console.log('A new message has arrived!');
});

Within the event handler, you can access the data sent via the data property of the event object:

1
2
3
4
self.addEventListener('message', event => {
console.log('A new message has arrived!');
console.log(event.data);
});

You can respond to the message by using the MessagePort.postMessage method:

1
2
3
4
5
6
7
self.addEventListener('message', event => {
console.log('A new message has arrived!');
console.log(event.data);

const data = { someData: 'hey' };
event.ports[0].postMessage(data);
});

To close a channel, you can use the close() method on the port:

1
2
3
4
5
6
7
8
self.addEventListener('message', event => {
console.log('A new message has arrived!');
console.log(event.data);

const data = { someData: 'hey' };
event.ports[0].postMessage(data);
event.ports[0].close();
});

An example with an iframe

Here’s an example showing communication between a document and an embedded iframe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<body>
<iframe src="iframe.html" width="500" height="500"></iframe>
<span></span>
</body>
<script>
const channel = new MessageChannel();
const display = document.querySelector('span');
const iframe = document.querySelector('iframe');

iframe.addEventListener('load', () => {
iframe.contentWindow.postMessage('Hey', '*', [channel.port2]);
}, false);

channel.port1.onmessage = event => {
display.innerHTML = event.data;
};
</script>
</html>

The iframe page source is simpler:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<script>
window.addEventListener('message', event => {
// send a message back
event.ports[0].postMessage('Message back from the iframe');
}, false);
</script>
</html>

In this example, a channel is created within the main document, and a message is sent to the iframe as soon as it loads. The iframe listens for messages and responds back accordingly.

An example with a Service Worker

Service Workers are isolated from the main thread and require communication via messages. Here’s how you can handle message passing with a Service Worker:

1
2
3
4
5
6
7
// `worker` is the service worker already instantiated

const messageChannel = new MessageChannel();
messageChannel.port1.addEventListener('message', event => {
console.log(event.data);
});
worker.postMessage(data, [messageChannel.port2]);

In the Service Worker code, you can add an event listener for the message event:

1
2
3
self.addEventListener('message', event => {
console.log(event.data);
});

The Service Worker can send messages back by posting them to messageChannel.port2:

1
2
3
self.addEventListener('message', event => {
event.ports[0].postMessage(data);
});

Browser support

The Channel Messaging API is supported by all major browsers, including older versions. You can find more details on browser support at caniuse.com.

tags: [“JavaScript”, “Channel Messaging API”, “iframes”, “Workers”, “Communication”]