The Broadcast Channel API seems like an alternative to postMessage or the Channel Messaging API (aka MessageChannel.) I've used both successfully in recent versions of Google Chrome to send Shared Array Buffers; however, I am having trouble sending a Shared Array Buffer using the Broadcast Channel API.
Mozilla's doc at https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel references the spec at https://html.spec.whatwg.org/multipage/web-messaging.html#broadcastchannel, which says:
For each destination in destinations...
- Let data be StructuredDeserialize(serialized, targetRealm). If this throws an exception, catch it, fire an event named messageerror at destination, using MessageEvent, with the origin attribute initialized to the serialization of sourceOrigin, and then abort these steps.
StructuredDeserialize is defined at https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize and seems to suggest it covers SharedArrayBuffers:
- Otherwise, if serialized.[[Type]] is "SharedArrayBuffer", then: If targetRealm's corresponding agent cluster is not serialized.[[AgentCluster]], then then throw a "DataCloneError" DOMException. Otherwise, set value to a new SharedArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]] and whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]].
Reading this, it seems to me that this should work, but I'm getting a message event where the data is simply null
.
If this were a security issue, I would expect to get a messageerror event instead of a message event.
Here's my minimal test case:
broadcast-test.html (must be served from an http server - won't work via file://)
<!DOCTYPE html>
<html>
<head><title></title></head>
<body>
<script src="broadcast-test.js"></script>
</body>
</html>
broadcast-test.js
const isThisTheWorker = this.document === undefined
const broadcastChannel = new BroadcastChannel('foo')
if (!isThisTheWorker) {
broadcastChannel.addEventListener('message', (event) => {
console.log('main received', event.data)
const sab = new SharedArrayBuffer(100)
broadcastChannel.postMessage({ hello: 'from main', sab })
})
var myWorker = new Worker('broadcast-test.js')
}
else {
broadcastChannel.addEventListener('message', (event) => {
console.log('worker received', event.data)
})
broadcastChannel.postMessage({ hello: 'from worker' })
}
Observed console output: (Chrome 84.0.4147.135 on Windows 10)
main received {hello: "from worker"}
worker received null
Is Google Chrome's implementation incorrect, or am I misunderstanding the spec?