Message Channels¶
Table of Contents
Message channels provide a mechanism to communicate across globals, including in cases where there is no client-side mechanism to establish a communication channel (i.e. when the globals are in different browsing context groups).
Markup¶
<script src="/resources/channels.sub.js"></script>
Channels can be used in any global and are not specifically linked to
testharness.js
.
High Level API¶
The high level API provides a way to message another global, and to execute functions in that global and return the result.
Globals wanting to recieve messages using the high level API have to
be loaded with a uuid
query parameter in their URL, with a value
that’s a UUID. This will be used to identify the channel dedicated to
messages sent to that context.
The context must call either global_channel
or
start_global_channel
when it’s ready to receive messages. This
returns a RecvChannel
that can be used to add message handlers.
- global_channel()¶
Create an unconnected channel defined by a uuid in
location.href
for listening for RemoteGlobal messages.- Returns
RemoteGlobalCommandRecvChannel – - Disconnected channel
- start_global_channel()¶
Start listening for RemoteGlobal messages on a channel defined by a uuid in location.href
- Returns
RemoteGlobalCommandRecvChannel – - Connected channel
- class RemoteGlobalCommandRecvChannel(recvChannel)¶
Handler for RemoteGlobal commands.
This can’t be constructed directly but must be obtained from global_channel() or start_global_channel().
- RemoteGlobalCommandRecvChannel.addMessageHandler(fn)¶
Add a handler for
postMessage
messages- Arguments
fn (
function()
) – Callback function that receives the message.
- RemoteGlobalCommandRecvChannel.close()¶
Close the channel and underlying websocket connection
- RemoteGlobalCommandRecvChannel.connect()¶
Connect to the channel and start handling messages.
- RemoteGlobalCommandRecvChannel.nextMessage()¶
Wait for the next
postMessage
message and return it (after passing it to existing handlers)- Returns
Promise – - Promise that resolves to the message.
- RemoteGlobalCommandRecvChannel.removeMessageHandler(fn)¶
Remove a handler for
postMessage
messages- Arguments
fn (
function()
) – Callback function to remove
Contexts wanting to communicate with the remote context do so using a
RemoteGlobal
object.
- class RemoteGlobal(dest)¶
Object representing a remote global that has a RemoteGlobalCommandRecvChannel
Create a new RemoteGlobal object.
This doesn’t actually construct the global itself; that must be done elsewhere, with a
uuid
query parameter in its URL set to the same as theuuid
property of this object.- Arguments
dest (
SendChannel|string()
) – Either a SendChannel to the destination, or the UUID of the destination. If ommitted, a new UUID is generated, which can be used when constructing the URL for the global.
- RemoteGlobal.uuid¶
UUID for the global
- RemoteGlobal.call(fn, ...args)¶
Run the function
fn
in the remote global, passing argumentsargs
, and return the result after awaiting any returned promise.- Arguments
fn (
function()
) – Function to run in the remote global.args (
Any()
) – Arguments to pass to the function
- Returns
Promise – - Promise resolving to the return value of the function.
- RemoteGlobal.close()¶
Close the channel and underlying websocket connections
- RemoteGlobal.connect()¶
Connect to the channel. Automatically called when sending the first message
- RemoteGlobal.disconnectReader()¶
Disconnect the associated RemoteGlobalCommandRecvChannel, if any, on the server side.
- Returns
Promise – - Resolved once the channel is disconnected.
- RemoteGlobal.postMessage(msg)¶
Post a message to the remote
- Arguments
msg (
Any()
) – The message to send.
Remote Objects¶
By default objects (e.g. script arguments) sent to the remote global
are cloned. In order to support referencing objects owned by the
originating global, there is a RemoteObject
type which can pass a
reference to an object across a channel.
- class RemoteObject(type, objectId)¶
Representation of a non-primitive type passed through a channel
- RemoteObject.delete()¶
Remove the object from the local cache. This means that future calls to
toLocal
with the same objectId will always returnnull
.
- RemoteObject.toLocal()¶
Return the local object referenced by the
objectId
of thisRemoteObject
, ornull
if there isn’t a such an object in this realm.
- RemoteObject.from(obj)¶
Create a RemoteObject containing a handle to reference obj
- Arguments
obj (
Any()
) – The object to reference.
Example¶
test.html
<!doctype html>
<title>call example</title>
<script src="/resources/testharness.js">
<script src="/resources/testharnessreport.js">
<script src="/resources/channel.js">
<script>
promise_test(async t => {
let remote = new RemoteGlobal();
window.open(`child.html?uuid=${remote.uuid}`, "_blank", "noopener");
let result = await remote.call(id => {
return document.getElementById(id).textContent;
}, "test");
assert_equals("result", "PASS");
});
</script>
child.html
<script src="/resources/channel.js">
<p id="nottest">FAIL</p>
<p id="test">PASS</p>
<script>
start_global_channel();
</script>
Low Level API¶
The high level API is implemented in terms of a channel abstraction. Each channel is identified by a UUID, and corresponds to a message queue hosted by the server. Channels are multiple producer, single consumer, so there’s only only entity responsible for processing messages sent to the channel. This is designed to discourage race conditions where multiple consumers try to process the same message.
On the client side, the read side of a channel is represented by a
RecvChannel
object, and the send side by SendChannel
. An initial
channel pair is created with the channel()
function.
- class Channel(uuid)¶
Abstract base class for objects that allow sending / receiving messages over a channel.
- Channel.uuid¶
UUID for the channel
- Channel.addEventListener(type, fn)¶
Add an event callback function. Supported message types are “connect”, “close”, and “message” (for
RecvChannel
).- Arguments
type (
string()
) – Message type.fn (
function()
) – Callback function. This is called with an event-like object, withtype
anddata
properties.
- Channel.close()¶
Close the channel and underlying websocket connection
- Channel.connect(onmessage)¶
Connect to the channel.
- Arguments
onmessage (
function()
) – Event handler function for the underlying websocket message.
- Channel.removeEventListener(type, fn)¶
Remove an event callback function.
- Arguments
type (
string()
) – Event type.fn (
function()
) – Callback function to remove.
- class SendChannel()¶
Send messages over a channel
- SendChannel.connect()¶
Connect to the channel. Automatically called when sending the first message.
- SendChannel.delete()¶
Disconnect this channel on the server side.
- SendChannel.disconnectReader()¶
Disconnect the associated RecvChannel, if any, on the server side.
- SendChannel.send(msg)¶
Send a message. The message object must be JSON-serializable.
- Arguments
msg (
Object()
) – The message object to send.