BroadcastChannel
BroadcastChannel(name)
Named asynchronous messaging channel shared by JSplitter panel and Worker realms.
BroadcastChannel is the recommended API for new many-to-many communication between independent JSplitter panels and Workers. Every open channel with the same name participates in the same process-wide JSplitter namespace. A sender publishes a value with postMessage(), and every other currently open channel with that name receives a MessageEvent. The sending channel itself does not receive its own message.
Unlike Worker.postMessage(), which addresses one specific Worker owned by one panel, BroadcastChannel is intentionally decoupled: the sender does not need to know which panels or Workers are listening.
window.NotifyOthers().The legacy
window.NotifyOthers() mechanism is synchronous and exposes the same live JavaScript value to other panels. This tightly couples the sender and receivers: changes made to a shared object can be visible across panels, and notification handling can directly affect the sender's execution.BroadcastChannel avoids these limitations by delivering messages asynchronously and using structured clone, so each recipient receives its own independent copy of the transmitted data.window.NotifyOthers() remains available for compatibility with existing scripts.
Quick start
Create two JSplitter panels.
In the first panel, create a channel and wait for messages:
const channel = new BroadcastChannel('my-script-state');
channel.onmessage = function (event) {
console.log('Panel A received:', event.data);
};
Then run this code in the second panel:
const channel = new BroadcastChannel('my-script-state');
channel.postMessage({
type: 'selection-changed',
playlist: 3,
index: 34
});
The other panel receives an independent structured-clone copy of the object. The sending channel object does not receive its own post. If the same realm (panel or worker) creates a second BroadcastChannel with the same name, that second channel is a separate receiver and can receive the message.
Panel and Worker use the same API
BroadcastChannel is also available inside Workers. This makes it useful when a Worker should publish state to panels or to other Workers without routing every message through its parent Worker object.
// PANEL
const channel = new BroadcastChannel('analysis-results');
channel.onmessage = event => {
console.log('Result:', event.data);
};
const worker = new Worker(`
const channel = new BroadcastChannel('analysis-results');
channel.postMessage({
type: 'ready',
worker: self.name
});
`, 'analyser');
Use direct Worker.postMessage() when the message belongs to one known parent/Worker pair. Use BroadcastChannel when the relationship is naturally publish/subscribe or when several panels and/or Workers may participate.
Channel names and scope
The constructor name is converted to a string. Use a stable, sufficiently specific name such as my.package.playback-state to avoid accidental collisions with unrelated scripts. Symbols cannot be converted to a channel name and throw a TypeError.
JSplitter does not have browser origins or storage partitions. All live JSplitter panel and Worker realms inside the same foobar2000 process share one BroadcastChannel namespace. Channels do not cross process boundaries and are not persistent; closing foobar2000 destroys the namespace.
Messages and structured clone
postMessage() uses the same structured-clone infrastructure as Worker messaging. Ordinary supported JavaScript values are copied, and supported JSplitter host wrappers can be reconstructed in the destination realm. See the Host objects in messages section of Worker for the current cloneable host-object list.
No ownership transfer
BroadcastChannel has no transfer-list argument. Its postMessage() accepts the message value only. This is different from direct Worker.postMessage() and Worker-global postMessage(), where a second transfer-list argument can move ownership of selected transferable objects to one specific destination.
A broadcast may have zero, one, or many receivers. There is no single receiver that can take ownership of a transferred resource, so BroadcastChannel always uses clone semantics. If a host object is cloneable, every receiver gets its own reconstructed representation and the sender's source object remains usable. No object is detached by BroadcastChannel.
// BroadcastChannel: clone. The sender keeps a usable bitmap.
const channel = new BroadcastChannel('artwork');
channel.postMessage({ bitmap: bitmap });
// bitmap is still usable here
// Direct Worker messaging: transfer ownership to one Worker.
worker.postMessage({ bitmap: bitmap }, [bitmap]);
// bitmap is detached here after a successful transfer
Use BroadcastChannel when several independent panels and/or Workers should receive cloned data by channel name. Use direct Worker messaging when one known destination should take ownership of a transferable resource. See Transferring ownership in Worker for the transfer model and the current transferable host-object list.
Serialization is performed synchronously by postMessage(). Before delivering the message, JSplitter first serializes it for all current receivers. If serialization fails for any receiver, postMessage() throws and no message is delivered, preventing a partial broadcast.
Serialization is also performed when there are no receivers. This matches the Web API behaviour, where posting a value that cannot be cloned can still throw even if nobody is listening.
JSplitter currently performs an independent structured serialization for each receiver because some native host-object snapshots are destination-owned. Consequently, side-effectful getters or Proxy traps in the value being serialized can run once per receiver. Avoid side effects in values passed to
postMessage().Receiving messages
Use onmessage or the inherited addEventListener('message', ...) API. Delivery is asynchronous. Messages posted sequentially by one sender are queued in the same order for a given receiver.
Trusted BroadcastChannel message events are MessageEvent objects. In JSplitter they use:
event.data— the reconstructed payload.event.origin— empty string.event.source—null.event.ports— empty frozen array.event.direction—"broadcast".
If a receiver cannot reconstruct a serialized value, its onmessageerror handler receives a MessageEvent whose data is null, direction is "broadcast", and errorMessage contains a JSplitter diagnostic string.
Lifetime and close()
Call close() when a BroadcastChannel instance is no longer needed. This disconnects only that instance from the named channel: it can no longer send or receive messages, while other instances with the same name continue to work normally. Closing is idempotent. A queued delivery is ignored if the destination instance is closed before it runs.
JSplitter automatically cleans up channels when a panel script is reloaded/unloaded or when a Worker terminates. An open channel with a message or messageerror listener is kept alive while its realm lives, matching the useful lifetime behaviour of the Web API; closing the channel releases that listener root. An unreachable open channel with no message listeners may be garbage-collected and removed automatically.
For the browser API model, see HTML Living Standard: BroadcastChannel.
Parameters
| Name | Type | Description |
|---|---|---|
name | * | Required channel name. The value is converted to a string; Symbol values throw TypeError. |
Throws
TypeError — If no name is supplied, if the constructor is called without new, or if the name cannot be converted to a string.