Message Channels¶
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 receive 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.
- static global_channel()¶
Create an unconnected channel defined by a uuid in
location.href
for listening for RemoteGlobal messages.- Returns:
RemoteGlobalCommandRecvChannel – - Disconnected channel
- static 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.
- static 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, with
type
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.